////////////////////////////////////////////////////////
//
// 2006.3创建 iamy
// 2006.11 修订 增加OnCheck OnQueryCheck事件
//
////////////////////////////////////////////////////////
unit MTreeView;
interface
uses
Windows, Classes, SysUtils, Messages, ComCtrls, Controls, CommCtrl;
Const
TVIS_CHECKED = $2000;
type
TMTreeViewQueryCheckEvent = procedure(Sender: TObject;Node: TTreeNode;var Cancheck: Boolean) of object;
TMTreeViewCheckEvent = procedure(Sender: TObject;Node: TTreeNode) of object;
TMTreeView = Class (TCustomTreeView)
private
FCheckBoxes: Boolean;
FEdting : Boolean;
FOnQueryCheck: TMTreeViewQueryCheckEvent;
FOnCheck: TMTreeViewCheckEvent;
procedure SetCheckBoxes(const Value: Boolean);
procedure SetComCtlStyle(Ctl: TWinControl;
Value: Integer;
UseStyle: Boolean);
procedure SetOnQueryCheck(const Value: TMTreeViewQueryCheckEvent);
proceduredo
CheckNode(Node : TTreeNode;Checked: Boolean);
proceduredo
Check(X,Y:Integer);
proceduredo
QueryNCheck(Node: TTreeNode);
procedure CNKeyDown(var Message: TWMKeyDown);
message CN_KEYDOWN;
procedure WMLButtonDown(var Message: TWMLButtonDown);
message WM_LBUTTONDOWN;
procedure CNNotify(var Message: TWMNotify);
message CN_NOTIFY;
procedure SetOnCheck(const Value: TMTreeViewCheckEvent);
protected
procedure Loaded;override;
public
function NodeChecked(Node: TTreeNode):Boolean;
procedure CheckNode(Node: TTreeNode;
Checked: Boolean;CallBackEvent : Boolean);
procedure CheckAllNode(Checked: Boolean;CallBackEvent : Boolean);
published
property CheckBoxes :Boolean read FCheckBoxes write SetCheckBoxes;
property OnQueryCheck : TMTreeViewQueryCheckEvent read FOnQueryCheck write SetOnQueryCheck;
property OnCheck: TMTreeViewCheckEvent read FOnCheck write SetOnCheck;
property Align;
property Anchors;
property AutoExpand;
property BevelEdges;
property BevelInner;
property BevelOuter;
property BevelKind default bkNone;
property BevelWidth;
property BiDiMode;
property BorderStyle;
property BorderWidth;
property ChangeDelay;
property Color;
property Ctl3D;
property Constraints;
property DragKind;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property HideSelection;
property HotTrack;
property Images;
property Indent;
property MultiSelect;
property MultiSelectStyle;
property ParentBiDiMode;
property ParentColor default False;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly;
property RightClickSelect;
property RowSelect;
property ShowButtons;
property ShowHint;
property ShowLines;
property ShowRoot;
property SortType;
property StateImages;
property TabOrder;
property TabStop default True;
property ToolTips;
property Visible;
property OnAddition;
property OnAdvancedCustomDraw;
property OnAdvancedCustomDrawItem;
property OnChange;
property OnChanging;
property OnClick;
property OnCollapsed;
property OnCollapsing;
property OnCompare;
property OnContextPopup;
property OnCreateNodeClass;
property OnCustomDraw;
property OnCustomDrawItem;
property OnDblClick;
property OnDeletion;
property OnDragDrop;
property OnDragOver;
property OnEdited;
property OnEditing;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnExpanding;
property OnExpanded;
property OnGetImageIndex;
property OnGetSelectedIndex;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDock;
property OnStartDrag;
{ Items must be published after OnGetImageIndex and OnGetSelectedIndex }
property Items;
end;
implementation
{ TMTreeView }
procedure TMTreeView.CheckNode(Node: TTreeNode;
Checked: Boolean;CallBackEvent : Boolean);
var
Cancheck : Boolean;
begin
CanCheck := True;
if CallBackEvent then
if Assigned(Self.FOnQueryCheck) then
Self.FOnQueryCheck(Self,Node,CanCheck);
if CanCheck then
begin
Self.DoCheckNode(Node,Checked);
if CallBackEvent then
if Assigned(Self.FOnCheck) then
Self.FOnCheck(Self,Node);
end;
end;
procedure TMTreeView.CheckAllNode(Checked: Boolean;CallBackEvent : Boolean);
var
i : Integer;
begin
for i := 0 to Self.Items.Count -1do
begin
Self.CheckNode(Self.Items,Checked,CallBackEvent);
end;
end;
procedure TMTreeView.DoCheck(X,Y:Integer);
var
Node: TTreeNode;
RectAll : TRect;
RectTxt : TRect;
CheckBoxOffSet : Integer;
CheckWidth : Integer;
begin
if Self.CheckBoxes then
begin
Node := GetNodeAt(X,Y);
if Node <> nil then
begin
RectAll := Node.DisplayRect(False);
RectTxt := Node.DisplayRect(True);
if Assigned(Self.Images) then
begin
CheckBoxOffset := Self.Images.Width + 4;
CheckWidth := Self.Images.Width ;
end else
begin
CheckBoxOffset := 1;
CheckWidth := 16;
end;
if (X <= RectTxt.Left - CheckBoxOffset) and (X > RectTxt.Left - CheckWidth - CheckBoxOffSet) and (Y >= RectAll.Top) and (Y < RectAll.Bottom) then
begin
Self.DoQueryNCheck(Node);
end;
end;
end;
end;
procedure TMTreeView.Loaded;
begin
inherited;
SetComCtlStyle(Self,TVS_CHECKBOXES,FCheckBoxes);
end;
function TMTreeView.NodeChecked(Node: TTreeNode): Boolean;
var
TvItem :TTVItem;
begin
TvItem.Mask := TVIF_STATE;
TvItem.hItem := Node.ItemId;
TreeView_GetItem(Node.TreeView.Handle, TvItem);
Result := (TvItem.State and TVIS_CHECKED) = TVIS_CHECKED;
end;
procedure TMTreeView.SetCheckBoxes(const Value: Boolean);
begin
if Value<>Self.FCheckBoxes then
begin
FCheckBoxes := Value;
SetComCtlStyle(Self,TVS_CHECKBOXES,Value);
if not value then
Self.Perform(CM_RECREATEWND,0,0);
end;
end;
procedure TMTreeView.SetComCtlStyle(Ctl: TWinControl;
Value: Integer;
UseStyle: Boolean);
var
Style: Integer;
begin
if Ctl.HandleAllocated then
begin
Style := GetWindowLong(Ctl.Handle, GWL_STYLE);
if not UseStyle then
Style := Style and not Value
else
Style := Style or Value;
SetWindowLong(Ctl.Handle, GWL_STYLE, Style);
end;
end;
procedure TMTreeView.SetOnQueryCheck(const Value: TMTreeViewQueryCheckEvent);
begin
FOnQueryCheck := Value;
end;
procedure TMTreeView.WMLButtonDown(var Message: TWMLButtonDown);
begin
Inherited;
do
Check(Message.XPos,Message.YPos);
end;
procedure TMTreeView.DoCheckNode(Node: TTreeNode;
Checked: Boolean);
var
TvItem :TTVItem;
begin
FillChar(TvItem, SizeOf(TvItem), 0);
with TvItemdo
begin
hItem := Node.ItemId;
Mask := TVIF_STATE;
StateMask := TVIS_STATEIMAGEMASK;
if Checked then
TvItem.State :=TVIS_CHECKED
else
TvItem.State :=TVIS_CHECKED shr 1;
TreeView_SetItem(Node.TreeView.Handle, TvItem);
end;
end;
procedure TMTreeView.CNNotify(var Message: TWMNotify);
var
Pt : TPoint;
Node : TTreeNode;
begin
Inherited;
with Messagedo
begin
//MessageBox(0,PChar(IntToStr(IDCtrl) + '_' + IntToStr(Self.Handle)),'',mb_OK);
PostMessage(TWinControl(Owner).Handle,WM_User,NMHdr^.code,0);
case NMHdr^.code of
-410 :
begin
Self.FEdting := True;
end;
-411 :
begin
Self.FEdting := False;
if Self.CheckBoxes then
begin
GetCursorPos(Pt);
Pt := Self.ScreenToClient(Pt);
Node := Self.GetNodeAt(Pt.X,Pt.Y);
Self.DoCheckNode(Node,not Self.NodeChecked(Node));
end;
end;
end;
end;
end;
procedure TMTreeView.SetOnCheck(const Value: TMTreeViewCheckEvent);
begin
FOnCheck := Value;
end;
procedure TMTreeView.DoQueryNCheck(Node: TTreeNode);
begin
Self.DoCheckNode(Node,Not Self.NodeChecked(Node));
Self.CheckNode(Node,Not Self.NodeChecked(Node),True);
end;
procedure TMTreeView.CNKeyDown(var Message: TWMKeyDown);
begin
inherited;
if Message.CharCode = VK_SPACE then
if Assigned(Self.Selected) then
begin
Self.DoCheckNode(Self.Selected,Not Self.NodeChecked(Self.Selected));
Self.DoQueryNCheck(Self.Selected);
Self.DoCheckNode(Self.Selected,Not Self.NodeChecked(Self.Selected));
end;
end;
end.