做过 treeview 上带checkbox的朋友 请进!(100分)

  • 主题发起人 主题发起人 令狐小侠
  • 开始时间 开始时间

令狐小侠

Unregistered / Unconfirmed
GUEST, unregistred user!
最近想做一个treeview上带checkbox的控件,
基本思想 是从 treeview继承....
查了一些资料..已经解决了 大部分问题...
现在有一个问题解决不了,大家帮看看
就是当 checkbox属性设为 false的时候,那个框框 因该 消失掉....但实际上是没消失?为什么

unit CheckBoxTreeview;

interface

uses
SysUtils, Classes, Controls, ComCtrls,windows,commctrl;
const
TVIS_Checked = $00002000;
TVIS_NotChecked = $00000800;
type
TCheckBoxTreeview = class(TTreeView)
private
fCheckbox: boolean;
fCheckChildrens: boolean;
procedure SetCheckbox(const Value: boolean);
function Getcheckbox: boolean;
function GetChecked(const node: Ttreenode): boolean;
procedure SetChecked(const node: Ttreenode; const Value: boolean);
{ Private declarations }
protected
procedure CreateParams(var params : TCreateParams);override;
{ Protected declarations }
public
constructor Create(AOwner: TComponent);
property Checked[const node : Ttreenode] : boolean read GetChecked write SetChecked;
{ Public declarations }
published
property CheckBox : boolean read Getcheckbox write SetCheckbox;
property CheckChildrens : boolean read fCheckChildrens write fCheckChildrens;

{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Samples', [TCheckBoxTreeview]);
end;

{ TCheckBoxTreeview }
procedure 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 //就是当 checkbox属性设为 false的时候,那个框框 因该 消失掉....但实际上是没消失?为什么
else
Style := Style or Value;
SetWindowLong(Ctl.Handle, GWL_STYLE, Style);
end;
end;

constructor TCheckBoxTreeview.Create;
begin
inherited;
SetComCtlStyle(self,$0100,fCheckbox);
end;

procedure TCheckBoxTreeview.CreateParams(var params: TCreateParams);
begin
inherited;
params.Style := params.Style or TVS_CHECKBOXES;
end;

function TCheckBoxTreeview.Getcheckbox: boolean;
begin
result := fcheckbox;
end;


function TCheckBoxTreeview.GetChecked(const node: Ttreenode): boolean;
var
ItemState:TTVITEM;
begin
result := false;
if node<>nil then
begin
itemstate.hItem := node.ItemId;
itemstate.state := TVIF_STATE;
treeview_getitem(node.GetHandle,itemState);
result := ((itemstate.state and TVIS_Checked )= TVIS_Checked);
end
else
raise exception.Create('node is nil');
end;



procedure TCheckBoxTreeview.SetCheckbox(const Value: boolean);
begin
fcheckbox := value;
SetComCtlStyle(self,TVS_CHECKBOXES,fcheckbox);
end;


procedure TCheckBoxTreeview.SetChecked(const node: Ttreenode;
const Value: boolean);
var
ItemState : TtvItem;
lsnode : Ttreenode;
begin
if node <> nil then
begin
fillchar(itemstate,sizeof(itemstate),0);
itemstate.mask := TVIF_STATE;
itemstate.hItem := node.ItemId;
itemstate.stateMask := TVIs_StateImageMask;
if value then
itemstate.state := TVIS_Checked
else
itemstate.state := TVIS_NotChecked;

treeview_Setitem(node.GetHandle,itemState);
if not fCheckChildrens then
exit
else
begin
if node.HasChildren then
begin
lsnode := node.GetNext;
if lsnode = nil then
exit;
while node.Level<lsnode.Level do
begin
fillchar(itemstate,sizeof(itemstate),0);
itemstate.mask := TVIF_STATE;
itemstate.hItem := lsnode.ItemId;
itemstate.stateMask := TVIs_StateImageMask;
if value then
itemstate.state := TVIS_Checked
else
itemstate.state := TVIS_NotChecked;

treeview_Setitem(lsnode.GetHandle,itemState);

lsnode := lsnode.GetNext;
if lsnode=nil then
exit;
end;
end
else
exit;
end;

end
else
raise Exception.Create('node is nil');
end;


end.
还有个问题,就是象 TVIS_Checked 这些 常量的 意思是什么...为什么这样定义.
望高手指点
 
有没有这么复杂啊,
其实只是没点一次,换个图片而已,
 
每个节点上都有ImageIndex,
切换这个就可以了,
 
切换图片的 方法 我知道!!只不过 感觉是 投机取巧!!
我想知道 真真 的实现方法?
大侠 可赐教?
 
TO
李翔鹏
就这种回答和顶有区别吗?
楼主给你帖个控件
unit extTreeView;

{
==============
TextTreeView 1.0 (1999-07-11)
==============

Enhaced TTreeView with 2- or 3-state checkboxes.

Freeware.

Copyright ?Roman Stedronsky 1999, Roman.Stedronsky@seznam.cz

All rights reserved. You may use this software in an application
without fee or royalty, provided this copyright notice remains intact.

types
-----
TCheckState defines 4 states for every node (No check,
Unchecked, Checked, Grayed)
public properties
-----------------
CheckStates[Index: integer] set/get the state for given node (by index)
published properties
--------------------
CheckBoxes when true, shows checkboxes
ThreeState when true, use 3-state cycle (un-checked-grayed)
when false, use 2-state cycle (unchecked-checked)
CheckBitmap defines visual appearance of checkboxes
(Width: 64 /4x16/, height: 16. See default one.)
events
------
OnStateClick occures after changing state via mouse
(Not when changing CheckStates!)
Note:
Every new node is in the state csNone by default (checkbox is not visible).
You must explicitly change it by CheckStates property. (You can also use
node's StateIndex as shown below, but why?)

StateIndex CheckState
-1 csNone
1 csUnchecked
2 csChecked
3 csGrayed
}

interface

uses
Windows, Messages, Classes, Graphics, Controls, ComCtrls, Commctrl;

type
TCheckState = (csNone, csUnchecked, csChecked, csGrayed);
TStateClickEvent = procedure(CheckState: TCheckState) of object;

TextTreeView = class(TCustomTreeView)
protected
{ internal variables }
FBitmap: TBitmap;
CheckStateImages: TImageList;
{ property variables }
FCheckBoxes: boolean;
FThreeState: boolean;
FStateClickEvent: TStateClickEvent;
{ property manipulation methods }
procedure FWriteCheckBoxes(Value: boolean);
function FReadCheckState(Index: integer): TCheckState;
procedure FWriteCheckState(Index: integer; Value: TCheckState);
procedure FWriteCheckBitmap(Value: TBitmap);
{ internal methods }
procedure ChangeCheckState(Node: TTreeNode);
procedure BitmapChanged(Sender: TObject);
public
{ overrided methods }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
property CheckStates[Index: integer]: TCheckState read FReadCheckState write FWriteCheckState;
published
property CheckBoxes: boolean read FCheckBoxes write FWriteCheckBoxes default true;
property ThreeState: boolean read FThreeState write FThreeState default false;
property CheckBitmap: TBitmap read FBitmap write FWriteCheckBitmap stored true default nil;
property OnStateClick: TStateClickEvent read FStateClickEvent write FStateClickEvent;
published
{ make TCustomTreeView propeties published (exclude StateImages) }
property Align;
property Anchors;
property AutoExpand;
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 Items;
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 TabOrder;
property TabStop default True;
property ToolTips;
property Visible;
property OnChange;
property OnChanging;
property OnClick;
property OnCollapsing;
property OnCollapsed;
property OnCompare;
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;
end;

procedure Register;

implementation

{$R XTreeView.res}

const
cCheckStatesBitmap = 'CheckStatesBitmap';

procedure Register;
begin
RegisterComponents('wzxphk', [TextTreeView]);
end;

{ property manipulation methods }

procedure TextTreeView.FWriteCheckBoxes(Value: boolean);
begin
FCheckBoxes := Value;
if FCheckBoxes then
StateImages := CheckStateImages
else
StateImages := nil;
end;

function TextTreeView.FReadCheckState(Index: integer): TCheckState;
begin
if (Index > -1) and (Index < Items.Count) then
if Items[Index].StateIndex = -1 then
Result := csNone
else
Result := TCheckState(Items[Index].StateIndex)
else
Result := csNone;
end;

procedure TextTreeView.FWriteCheckState(Index: integer; Value: TCheckState);
begin
if (Index > -1) and (Index < Items.Count) then
if Value = csNone then
Items[Index].StateIndex := -1
else
Items[Index].StateIndex := integer(Value);
end;

procedure TextTreeView.FWriteCheckBitmap(Value: TBitmap);
begin
if Value = nil then
begin
FBitmap.Handle := LoadBitmap(HInstance, cCheckStatesBitmap)
end
else
FBitmap.Assign(Value);
CheckStateImages.Clear; // Does Clear free memory or not?
CheckStateImages.Add(FBitmap, nil);
end;

{ internal methods }

procedure TextTreeView.BitmapChanged(Sender: TObject);
begin
CheckStateImages.Clear;
CheckStateImages.Add(FBitmap, nil);
end;

procedure TextTreeView.ChangeCheckState(Node: TTreeNode);
begin
if CheckStates[Node.AbsoluteIndex] = csUnchecked then
CheckStates[Node.AbsoluteIndex] := csChecked
else if CheckStates[Node.AbsoluteIndex] = csChecked then
begin
if FThreeState then
CheckStates[Node.AbsoluteIndex] := csGrayed
else
CheckStates[Node.AbsoluteIndex] := csUnchecked
end
else
CheckStates[Node.AbsoluteIndex] := csUnchecked;
end;

{ overrided methods }

constructor TextTreeView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
CheckStateImages := TImageList.Create(Self);
FBitmap := TBitmap.Create;
FBitmap.OnChange := BitmapChanged;
FBitmap.Handle := LoadBitmap(HInstance, cCheckStatesBitmap);
StateImages := CheckStateImages;
FThreeState := false;
CheckBoxes := true;
ParentColor := False;
TabStop := True;
end;

destructor TextTreeView.Destroy;
begin
FBitmap.Free;
CheckStateImages.Free;
inherited Destroy;
end;

procedure TextTreeView.CNNotify(var Message: TWMNotify);
var
Node: TTreeNode;
Point: TPoint;
Position: DWORD;
begin
case message.nmhdr.code of
NM_CLICK:
begin
Position := GetMessagePos;
Point.x := LoWord(Position);
Point.y := HiWord(Position);
Point := ScreenToClient(Point);
Node := GetNodeAt(Point.x, Point.y);
if (Node <> nil) then
begin
if htOnStateIcon in GetHitTestInfoAt(Point.x, Point.y) then
begin
ChangeCheckState(Node);
if Assigned(FStateClickEvent) then
FStateClickEvent(CheckStates[Node.AbsoluteIndex]);
end;
end;
end;
end;
inherited;
end;

end.
 
To 网中戏:
我刚刚编译了一下你的控件,可以成功,但使用的时候提示找不到xTreeView.res.
 
xTreeView.res是资源文件。就是几张图。无法帖上。你自己画几张图制成资源
也可以给出EM发给你
 
太感谢 网兄了....dfw需要这样的人啊。。。。。。。。
先研究,研究。。。。。。。。。多谢
 
麻烦网兄,抄一份给我,多谢。。。
terryapp1981@gmail.com
 
看了以下 网兄 的好象 也是 用 图片 替换来 实现的啊!
有谁知道我的问题出在那里啊?
 
麻烦网兄,抄一份给我,多谢。。。
dey-999@163.com
 
兄弟们 直接拷过去 不就行了,非要发到邮箱啊。。。。。。
真是的。。。。。。。。。
 
上面代码和资源文件已经上传。下载地址
www.delphibbs.com/keylife/images/u173415/checktree.rar
 
网中戏,谢谢了,刚刚可以使用。我还有两个肤浅的问题请教一下:
1、我在StateClick事件中写如下代码ShowMessage(IntToStr( eTV.Selected.Index));,从显示的信息可以看出,每次点击check框的时候,selected并没有马上切过来,所以显示的index还是上次selected的信息。你是怎么搞定的。
2、在设置CheckState的时候,使用的是Index来作为索引,而不是TTreeNode,我觉得好麻烦,因为我一般是先知道是TTreeNode,然后找到它对应的Index来设置。是不是我方法不对。
 
第二个问题应该是我搞晕了,不好意思 :)
 
你们谁是楼主呀?谁能给分[:D]。
选和不选就是1和2
 
我是楼主,可是 我的问题 还没解决,放心好了,一定放分的!
 
后退
顶部