treeview的使用

一:TreeView.Items[0].Expanded := True; // 展开第一个节点
二:TreeView.Items[0].Item[0].Selected := True; // 移动到第一个节点的第一个子节点  
找当前节点的下一个节点,按序号找如下:
if treeview1.Selected.GetNext<>nil then
treeview1.Selected.GetNext.Selected:=true;
TreeView1.SetFocus;

找当前节点的下一个同层兄弟如下:
if treeview1.Selected.getNextSibling<>nil then
treeview1.Selected.getNextSibling.Selected:=true;
TreeView1.SetFocus;
TreeView.Selected.getPrevSibling  //当前选中节点的上一个兄弟节点
TreeView.Selected.Parent          //  当前选中节点的父节点  

getfirstchild是跳到该节点子结点中的第一个
getlastchild是跳到该节点子结点中的最后一个

如果你是想跳到同层兄弟结点的第一个
if treeview1.selected.parent<>nil then
treeview1.selected.parent.getfirstchild.selected:=true
else
treeview1.items.item[0].selected:=true;

如果你是想跳到同层兄弟结点的最后一个
if treeview1.selected.parent<>nil then
treeview1.selected.parent.getlastchild.selected:=true
else
treeview1.Items.Item[treeview1.Items.Count-1].Selected:=true;
TreeView的使用方法


基本信息:
TreeView 是一个显示树型结构的控件,每一个节点都是一个新类,
使用具有代表性
每个节点都有四个值:
TEXT:显示文字 Image Index:显示图形序号
Selected Index:
State Index:

(1)建立目录项(本例中使用的TREEVIEW名称为:TvwTips)

增加根目录下的节点:(节点)
var
CatNode : TTreeNode; //先建立一个TREEVIEW使用的子对象
begin
TvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上
{ 在根标题下建立一个新的子标题 }
CatNode := TvwTips.Items.AddChild(
TvwTips.Items.GetFirstNode,'New Category' );
CatNode.ImageIndex := 1;
CatNode.SelectedIndex := 2;
CatNode.EditText; { 允许用户改变这个标题 }
end;

增加下一级目录(内容):
var
ParentNode, TipNode : TTreeNode; //先建立TREEVIEW使用
的子对象
VersionNum : Integer;
begin
TvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上
VersionNum := TMenuItem( Sender ).Tag; { Ver num of new tip }
ParentNode := TvwTips.Selected; { 取出当前的选中节点 }
if ParentNode.Level = nlTip then{ Parent cannot be a tip node }
ParentNode := TvwTips.Selected.Parent;

TipNode := TvwTips.Items.AddChildObject( ParentNode,'New
Subject',Pointer( VersionNum ) );
TipNode.ImageIndex := 3; { Normal tip bitmap }
TipNode.SelectedIndex := 4; { Highlighted tip bitmap }
TipNode.MakeVisible; { Move new tip node into view }
TipNode.EditText; { Immediately allow user to edit subject }
EnableTreeViewFunctions( TipNode.Level );
RtfTip.Clear;
RtfTip.Modified := False;
end;

(2)说明
TvwTips.Items.GetFirstNode 返回TREEVIEW的第一个节点,函数类型为
:TTreeNode
TvwTips.Items.Count 返回当前TreeView的全部节点数,整数
TvwTips.Selected.Level 返回当前选中节点的在目录树中的级别,
根目录为0
TvwTips.Selected.Parent 返回当前选中节点上级节点,函数类型为
:TTreeNode

三、下面这段程序是用TREEVIEW连数据库及一些操作:
unit bmzd;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 StdCtrls, ComCtrls, Db, DBTables, ImgList, Buttons, ExtCtrls, Grids,
 DBGrids;

type
 Tfrmbmzd = class(TForm)
   Panel1: TPanel;
   cmd_new: TBitBtn;
   cmd_delete: TBitBtn;
   cmd_exit: TBitBtn;
   tvwcode: TTreeView;
   ScrollBox1: TScrollBox;
   GroupBox2: TGroupBox;
   Label3: TLabel;
   Label2: TLabel;
   Label1: TLabel;
   Label4: TLabel;
   Label5: TLabel;
   Edit2: TEdit;
   Edit3: TEdit;
   Edit4: TEdit;
   Edit5: TEdit;
   ImageList1: TImageList;
   Edit1: TEdit;
   cmd_save: TBitBtn;
   cmd_update: TBitBtn;
   procedure FormShow(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure cmd_newClick(Sender: TObject);
   procedure cmd_deleteClick(Sender: TObject);
   procedure Edit2KeyPress(Sender: TObject; var Key: Char);
   procedure tvwcodeChange(Sender: TObject; Node: TTreeNode);
   procedure cmd_updateClick(Sender: TObject);
   procedure BitBtn2Click(Sender: TObject);
   procedure tvwcodeClick(Sender: TObject);
 private
   { Private declarations }
     function LoadCode(crTbl:TDBDataSet):Integer;
function GetLevel(sFormat,sCode:String):Integer;

 public
   { Public declarations }
 end;

var
 frmbmzd: Tfrmbmzd;
 ii:integer;
 tv:ttreenode;
 const
SCodeFormat = '222222';   //科目代码结构
SFirstNodeTxt   = '部门分类';

implementation

uses dm;


{$R *.DFM}

function tfrmbmzd.LoadCode(crTbl:TDBDataSet):Integer;
var NowID,sName,ShowTxt:String;
i,Level:Integer;
MyNode:array[0..6]of TTreeNode;
//保存各级节点,最长支持6级(重点)
begin
Screen.Cursor:=crHourGlass;
Level:=0;
With frmdm.tabbm do
begin
try
if not Active then Open;
First;
tvwCode.Items.Clear;
//以下是增加第一项
MyNode[Level]:=tvwCode.Items.Add
(tvwCode.TopItem,SFirstNodeTxt);
MyNode[Level].ImageIndex:=0;
MyNode[Level].SelectedIndex:=0;
//以上是增加第一项
While Not Eof do
begin
NowID:=Trim(FieldByName('bumeng_id').AsString);
ShowTxt:=FieldByName('bumeng_name').AsString;
Level:=GetLevel(SCodeFormat,NowID);
//返回代码的级数
//以下是增加子项
//以下用上一级节点为父节点添加子节点
if Level>0 then//确保代码符合标准
begin
  MyNode[Level]:=tvwCode.Items.AddChild
(MyNode[Level-1],NowID+' '+ShowTxt);
  MyNode[Level].ImageIndex:=1;
 MyNode[Level].SelectedIndex:=2;
end;  
//以上是增加子项
Next;
end;
finally
Close;
end;
end;
MyNode[0].Expand(False);//将首节点展开
Screen.Cursor:=crDefault;
end;
//以上函数将Code.db表中的科目代码和科目代码名称显示出来

//下面函数的功能是返回一代码的级数,
//参数sFormat传递科目代码结构;
//参数sCode传递某一科目代码
function tfrmbmzd.GetLevel
(sFormat,sCode:String):Integer;
var i,Level,iLen:Integer;
begin
Level:=-1;//如果代码不符合标准,则返回-1
iLen:=0;
if (sFormat<>'')and(sCode<>'')then
for i:=1 to Length(sFormat) do
begin
iLen:=iLen+StrToInt(sFormat[i]);
if Length(sCode)=iLen then
begin
  Level:=i;
  Break;
end;
end;
Result:=Level;
end;

procedure Tfrmbmzd.FormShow(Sender: TObject);
begin

if not frmdm.tabbm.active then frmdm.tabbm.Open;
frmdm.tabbm.IndexFieldNames:='BUMENG_ID';
//按字段aCode排序(不要漏掉)

LoadCode(frmdm.tabbm);



end;

procedure Tfrmbmzd.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;

procedure Tfrmbmzd.cmd_newClick(Sender: TObject);
begin
tvwcode.SetFocus ;
if tvwcode.selected.AbsoluteIndex<>0 then
begin
cmd_delete.Enabled:=true;
cmd_update.Enabled:=true;
cmd_save.Enabled :=true;
if not frmdm.tabbm.Active then frmdm.tabbm.Open;

edit1.text:=frmdm.tabbm.Fields[0].asstring;
end;
tvwcode.SetFocus ;
tvwcode.Items.AddChild(tvwcode.selected,'新建部门');
if   tvwcode.Selected.HasChildren then
begin
if tvwcode.Selected.GetLastChild.index+1>9 then
 edit2.text:=inttostr(tvwcode.Selected.GetLastChild.index+1)
 else
edit2.text:='0'+inttostr(tvwcode.Selected.GetLastChild.index+1);
edit3.text:='新建部门';
edit2.Enabled:=true;
edit3.Enabled:=true;
end
else
begin
edit2.text:='01';
edit3.text:='新建部门';
edit2.Enabled:=true;
edit3.Enabled:=true;
end;
if not frmdm.tabbm.Active then frmdm.tabbm.Open;
frmdm.tabbm.edit;
frmdm.tabbm.Append;
cmd_new.Enabled :=false;
cmd_delete.Enabled :=false;
cmd_update.Enabled :=false;
cmd_save.Enabled :=true;
//新建下级部门

tvwcode.Selected.GetLastChild.Selected:=true;
//设选择
tv:=tvwcode.Selected ;
tvwcode.autoExpand:=true;
tvwcode.SetFocus ;


end;

procedure Tfrmbmzd.cmd_deleteClick(Sender: TObject);
var
I:integer;
seno,setext:string;
begin
if tvwcode.Selected.HasChildren=true then
begin
application.messagebox('该部门包含下级,不能删除','提示',MB_OKCANCEL+mb_iconquestion ) ;
end
else
begin
if   application.messagebox('你确实要删除当前部门吗','提示',MB_OKCANCEL+mb_iconquestion )=IDOK then
begin
setext:=tvwcode.selected.text;
i:=0;
while setext[i] <> ' ' do
begin
I := I + 1;
seno:=seno+setext[i];
end;
if not frmdm.tabbm.Active then frmdm.tabbm.Open;
frmdm.tabbm.setkey;
frmdm.tabbm.Fields[0].asstring:=seno;
if frmdm.tabbm.GotoKey then
begin
frmdm.tabbm.edit;
frmdm.tabbm.Delete;
end;
tvwcode.Selected.Delete ;
cmd_new.Enabled :=true;
tvwcode.autoExpand:=true;
 tvwcode.SetFocus ;
end;
end;

end;

procedure Tfrmbmzd.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
if key  in ['0'..'9',Chr(vk_Back)]   then

else
begin
key:=#0;
application.messagebox('','',mb_ok);

end;
end;

procedure Tfrmbmzd.tvwcodeChange(Sender: TObject; Node: TTreeNode);
var
i,lev:integer ;
strr,seno,setext:string;
begin
if cmd_new.Enabled =true then
begin
if tvwcode.selected.AbsoluteIndex<>0   then
begin
cmd_delete.Enabled:=true;
cmd_update.Enabled:=true;
cmd_save.Enabled :=true;
setext:=tvwcode.selected.text;
i:=0;
while setext[i] <> ' ' do
begin
I := I + 1;
seno:=seno+setext[i];
end;
if not frmdm.tabbm.Active then frmdm.tabbm.Open;
frmdm.tabbm.setkey;
frmdm.tabbm.Fields[0].asstring:=seno;
frmdm.tabbm.GotoKey;
strr:='';

case tvwcode.Selected.Level of
2: strr:=copy(frmdm.tabbm.fields[0].asstring,1,2);
3: strr:=copy(frmdm.tabbm.fields[0].asstring,1,4);
 end;
 edit1.text:=strr;
//加上级编码
edit3.text:=frmdm.tabbm.Fields[1].asstring;
//本级编码

edit2.text:=copy(frmdm.tabbm.fields[0].asstring,length(frmdm.tabbm.fields[0].asstring)-1,2);

end
else
begin
edit1.text :='';
edit2.text :='';
edit3.text :='部门分类';
cmd_delete.Enabled :=false;
cmd_update.Enabled :=false;
end;
end;
end;


procedure Tfrmbmzd.cmd_updateClick(Sender: TObject);
var
i:integer;
begin
for i:=0 to ComponentCount-1  do
begin
if (Components[I]  is tedit ) then
(Components[I]  as tedit).enabled:=false;
end;
for i:=0 to ComponentCount-1  do
begin
if (Components[I]  is tbitbtn ) then
(Components[I]  as tbitbtn).enabled:=true;
end;
if tvwcode.Selected.AbsoluteIndex<>0 then
begin

if not frmdm.tabbm.Active  then frmdm.tabbm.Open;
frmdm.tabbm.Edit;
frmdm.tabbm.Fields[0].asstring:=edit1.text+edit2.text;
frmdm.tabbm.Fields[1].asstring:=edit3.text;
try
frmdm.tabbm.Post;
//表的保存
except
on edbengineerror do
begin
edit2.Enabled :=true;
 application.messagebox('编号不能重复,请重新输入','提示',MB_OK+mb_iconquestion ) ;
exit;
end;
 end;
tvwcode.Selected.Text:=edit1.text+edit2.text+' '+edit3.text;
tvwcode.SetFocus ;
//修改树
end;

cmd_new.Enabled :=true;
edit2.Enabled :=false;
end;

procedure Tfrmbmzd.BitBtn2Click(Sender: TObject);
begin
cmd_new.Enabled :=false;
cmd_delete.Enabled :=false;
edit2.enabled:=true;
edit3.Enabled :=true;

end;

procedure Tfrmbmzd.tvwcodeClick(Sender: TObject);
var
i:integer;
begin
if cmd_new.Enabled =false then
begin
application.MessageBox('当前是修改状态,请单击保存按钮','提示',mb_ok);
tv.Selected :=true;
end;
if  tvwcode.selected.AbsoluteIndex=0 then
begin
for i:=0 to ComponentCount-1  do
begin
if (Components[I]  is tedit ) then
(Components[I]  as tedit).enabled:=false;
end;
for i:=0 to ComponentCount-1  do
begin
if (Components[I]  is tbitbtn ) then
(Components[I]  as tbitbtn).enabled:=false;
cmd_new.Enabled :=true;
cmd_exit.Enabled :=true;
end;
end;
end;
end

四、使用概述
树形图(Treeview)是Win95下新增加的通用显示部件(Common Control,在COMCTL32.DLL中)之一,从Delphi2.0开始也增加了相应的控件Treeview,用于取代原Outline控件。由于树形图结构较复杂,使用起来常不知如何下手。这里就使用中的一些问题作些介绍。
   Treeview用于显示按照树形结构进行组织的数据,这在实际当中用途还是比较广泛的,如计算机中的文件系统(Windows95中的资源管理器)、企业或公司的组成结构等等。Treeview控件中一个树形图由节点(TreeNode)和连接线组成。TtreeNode是TTreeview的基本组成单元。一个树的节点又包含文本(Text)和数据(Data)。Text为String类,Data则为无定形指针(Untyped Pointer),可以指向一个与节点相联系的数据结构。
  每一个节点下子节点形成这一节点的Items属性,当前节点有一个唯一的Index(TreeNode的Index属性),用于说明子节点在Items中的位置,每一个节点下的子节点是顺序编号的,第一个是0,第二个是1,依次类推。用IndexOf方法获得子节点的顺序,绝对顺序(AbsoluteIndex)则是指从Treeview第一个项开始的顺序值,第一个是0,如此推下去。Item属性则根据Index的值返回当前节点的第Index个子节点。Count则表明属于此项的所有子节点的数量。用MoveTo方法将Item由一个位置移到另一个位置。
  Expanded属性表明是否所有的子项都全部展开(包括子项的子项),为True表示全部展开。IsVisible属性表明一个项是否在树中能被看到,如果树全部展开那么这个Item是肯定可以被看到。HasChildren属性表明一个项是否有子项。 GetFirstChild, GetLastChild, GetPrevChild, and GetNextChild分别返回当前项子项的第一个、最后一个和前一个、后一个项。GetNextSibling and GetPrevSibling则返回在同一Level下的下一个和上一个项。GetNextVisible and GetPrevVisible则返回能看得到的下一个和上一个项。如果一个节点有Parent,则HasAsParent方法返回True. Parent为当前项的父项。Focused属性确定焦点是否落在此节点上,被Focus时会一个标准的方框围住。很显然,只有一个节点会被聚焦。 Selected属性表明一个节点是否被选中,同样只有一个节点会被选中。DropTarget属性表明节点在拖动操作中是源还是目标。
1.添加、删除、修改节点:
静态的方法可以在设计时通过Items的编辑器设置各节点的内容。
在添加和删除前必须保证有节点被选中(Treeview.Selected = nil)
用AddFirst, AddFirstChild, AddChild等先添加根节点,如Treeview.Items.AddFirst( nil, 'Root');
然后以此为基础,添加此项的子节点。

删除节点
Treeview.Selected.Delete
编辑节点内容
Treeview.Selected.EditText
注意:由于根节点没有父节点 (TTreeNode.Parent= nil)
此外,在大批量添加数据到Treeview中时最好使用
  TreeView.Items.BeginUpdate;
  添加节点
  TreeView.Items.EndUpdate
这样能加快显示速度。

2.在节点上添加图象
Treeview中几个与图象相关的属性:
  SelectedIndex:当节点被选中时在TimageList 中选什么样的图象
  OverlayIndex:选那副图象作为掩图(一幅图象透明地显示在另一幅图象的前面),比如一个节点不可用时加一副X图象在其前面。
  ImageIndex:在常态时选用的图的序号
  StateIndex: 在StateImages这个ImageList中对应的序号,-1时不显示图象
  比较典型的,象在文件管理器中的所显示的一样,Treeview控件在节点之前也可以显示图象。在Form中放置一ImageList控件,加入几个图片,分别被Index为0,1,…在Treeview的Image属性项填入你所加入的ImageList的控件名称。TreeNode的ImageIndex表示节点未被选中时(Selected=nil)的图片序号,SelectedIndex表示节点被选中时图片序号。

3.关于Level
Level的概念可以用下图表示:
Level0   Level1 Level2

4.排序
SortType决定什么时候进行排序;
TreeView.AlphaSort对节点进行排序,如果不能满足要求,你可以定义自己的CustomSort方法。
5.Drag&Drop操作,与标准的拖放操作使用方法一样。

五、一个例子:
 首先,在库的构建上要有一定策略以下几个字段非常重要:
'codeID'      代码集名称 (例如:'AB')
'code'        节点代码   (例如:'新疆'节点的代码为'65','乌鲁木齐'的节点代码为'6501'等)
'description' 节点描述   (例如:如上面的'新疆'、'乌鲁木齐'等)
'pptr'        父节点代码 (例如:'乌鲁木齐'节点的父代码为'65',最高层节点的父节点代码可同其代码集,例如:'新疆'的父节点为                              'AB')
'cptr'        子节点标识 (例如:该节点是否有下级节点,有则取值'1',没有则取值'0')



建立树由两部分构成:

procedure TForm1.FormActivate(Sender: TObject);
var
 code_ID,new_sql,node_text,table_name:string;
 new_node:Ttreenode;
begin

//要传递的参数
code_ID:='AB';
table_name:='sr_codeitem';

//********
treeview1.Items.BeginUpdate;

//清空所有项目
treeview1.Items.Clear;


new_sql:='select * from '+ table_name + ' where codeID='+''''+code_ID+''''
        + ' and '+'pptr='+''''+code_ID+'''';


//数据集中先筛选出所有要增加节点
with dm1.Query1 do
begin
  close;
  sql.Clear;
  sql.Add(new_sql);
  open;
  //增加第一层节点
  while not eof do
    begin
      node_text:=fieldbyname('code').asstring;
      node_text:=node_text+'   '+fieldbyname('description').asstring;
      new_node:=treeview1.Items.add(nil,node_text);
      new_node.HasChildren:=true;
      next;
    end;//end while
end;//end with

treeview1.Items.EndUpdate;
end;

procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean);
var
 new_sql,node_text,child_text,code_ID,table_ID:string;
 child_node:Ttreenode;
begin
//获取参数
code_ID:='AB';
table_ID:='sr_codeitem';

treeview1.Items.BeginUpdate;
node_text:=node.Text;
//截取所点击节点的code
node_text:=copy(node_text,1,pos(' ',node_text)-1);
with dm1.Query1 do
begin
  close;
  sql.Clear;
  new_sql:='select * from '+table_ID+' where pptr='+''''+node_text+'''' + ' and codeID='
            +''''+code_ID+'''';
  sql.Add(new_sql);
  open;//定位所点的项
  //清除原来的下级节点
  node.DeleteChildren;
  while not eof do
     begin//增加下级节点
       child_text:=fieldbyname('code').asstring+'   '+fieldbyname('description').asstring;
       child_node:=treeview1.Items.AddChild(node,child_text);
       if fieldbyname('cptr').asstring='1' then
          child_node.HasChildren:=true;
          next;
     end;//end while

end;//end with
treeview1.Items.EndUpdate;
end;
 第二部分:在 treeview 的onExpanding 事件中添加如下代码
procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean);
var
 new_sql,node_text,child_text,code_ID,table_ID:string;
 child_node:Ttreenode;
begin
//获取参数
code_ID:='AB';
table_ID:='sr_codeitem';

treeview1.Items.BeginUpdate;
node_text:=node.Text;
//截取所点击节点的code
node_text:=copy(node_text,1,pos(' ',node_text)-1);
with dm1.Query1 do
begin
  close;
  sql.Clear;
  new_sql:='select * from '+table_ID+' where pptr='+''''+node_text+'''' + ' and codeID='
            +''''+code_ID+'''';
  sql.Add(new_sql);
  open;//定位所点的项
  //清除原来的下级节点
  node.DeleteChildren;
  while not eof do
     begin//增加下级节点
       child_text:=fieldbyname('code').asstring+'   '+fieldbyname('description').asstring;
       child_node:=treeview1.Items.AddChild(node,child_text);
       if fieldbyname('cptr').asstring='1' then
          child_node.HasChildren:=true;
          next;
     end;//end while

end;//end with
treeview1.Items.EndUpdate;
end;  

六、让我们一个一个来回答:
第一个:取出节点的text属性值,赋给Richedit的Lines.text即可;
例如: self.RichEdit1.Lines.text:= self.Treeview1.selected.text;
第二个:TtreeView控件有函数保存和载入树的结构到文件
例如:self.Treeview1.SaveToFile('文件名');//保存结构
     self.TreeView1.LoadFromFile('文件名');//载入结构
第三个:TreeView的每个节点都有ItemID(句柄),AbsoluteIndex(相对于树头节点的索引位置),
Index(在当前层的位置),Level(本节点的层数)通过访问这些可以知道其位置;
例如:self.TtreeView1.selected.ItemID;//返回句柄
    self.TreeView1.selected.Level;//返回层数
    self.TreeView1.Items.count//返回所有节点的个数;
**寻找某一个节点的话,就只有写一个循环来遍历整个树,直到找到符合条件的节点为止,
关于查找节点的代码我也在想,先参考上面同志们的回答吧;

??**为某个节点加上子节点,例如:
var NewNode:TTreeNode;
begin
NewNode:=self.Treeview1.Items.addChild(self.Treeview1.Items[3],'新的字节点');
//为self.Treeview1.Items[3]加上一个字节点,标签是'新的字节点',
//还有其他的ADD方法,可以查找Delphi帮助
//然后可以给刚加上去的子节点赋值;
NewNode.ImageIndex:=n;
NewNode.SelectedIndex:=M;
NewNode.Data:=X;//注意X是一个指针类型;关于这方面的帮助
//可以找一下TTreeNode.Data 属性例子
end;
??**想选中某个节点:self.TreeView1.Items[n].selected:=true;//这样就选中了
??**展开某节点就容易了:self.TreeView1.Items[n].Expand;//展开啦!
//想合上就用Collapse(Recurse: Boolean)函数,
总之呢,去查一下TtreeNode的帮助吧!
??**清除某节点下的所有子节点,用DeleteChildren是没错的,例如:
self.Treeview1.Items[n].DeleteChildren;//OK,下面都没了!

七、query1.close;
query1.sql.clear;
query1.sql.add('select * from t08 order by t0801');
try
  query1.open;
except
  on e:exception do
  begin
     application.MessageBox(pchar('打开数据库文件失败!'+#13+#13+e.Message),'错误信息',16);
     close;
     exit;
  end;
end;
//创建结构树
while not query1.eof do
begin
   s:=trim(query1.fields[0].asstring);
   case length(s) of
   2:begin
        tv1.Selected:=tv1.items.add(nil,trim(query1.fields[1].asstring));
        tv2.Selected:=tv2.items.add(nil,trim(query1.fields[0].asstring));
     end;
   4:begin
        p1:=tv1.items.addchild(tv1.Selected,trim(query1.fields[1].asstring));
        p2:=tv2.items.addchild(tv2.Selected,trim(query1.fields[0].asstring));
     end;
   6:begin
        tv1.Items.addchild(p1,trim(query1.fields[1].asstring));
        tv2.Items.addchild(p2,trim(query1.fields[0].asstring));
     end;
   end;
   query1.next;
end;
query1.close;
if tv1.Items.Count>0 then
begin
 tv1.Selected:=tv1.Items[0];
 tv1.Selected.Expand(true);
end;
tv1.OnClick(self);  
八、clear速度慢的问题
 问题的关键在于Clear方法会一个一个地删除每个Node,
于是TreeView不断刷新,所以速度就....
代码修正一下:
with MyTreeView.Items do
<B>try</B>
BeginUpdate;
Clear;
<B>finally</B>
EndUpdate;
<B>end;</B>

另外
1、你现在遇到的问题是大量删除,
如果是大量插入,也应该同样处理
2、ListView有同样问题,注意
其他Windows控件也有,但不很明显
比如Memo、RichEdit等等
总之,凡大量数据修改的情况下,
应该注意BeginUpdate和EndUpdate
3、<B>BeginUpdate和EndUpdate应该一一对应</B>,
因为Delphi实际上是用<B>计数器</B>来处理的,
如果忘了EndUpdate,
或者BeginUpdate比EndUpdate次数多,
可能导致控件不刷新了
九、用treeview做权限管理
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2242766    

各位大虾:
  我想在TreeView进行用户权限设置,具体思路为:
 TreeView中的所有节点由数据表动态添加,在每一个节点上出先一下选择框,象CHECK的那一种,当选择框打勾时,说明此菜单用户可用,否则不可用。请问怎样实现?
谢谢!在线等。  


来自:dana, 时间:2003-10-21 9:37:00, ID:2242812
可以用dbtreeview有复选框的功能可以用,很简单就可以实现的.  


来自:xinren_111, 时间:2003-10-21 9:44:00, ID:2242829
写程序吧,不过不是一两句搞定的.
'select * from form ';  //首先搜库

TreeViewX.Items.AddChild(TreeViewX.Items.Item[i],['字段名']);  //用循环语句

这样一来就可以把库中需要排列字段按节点列出  


来自:不知道_0909, 时间:2003-10-21 9:47:00, ID:2242835
添加上这过程,就可以出现checkbox
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
    else Style := Style or Value;
    SetWindowLong(Ctl.Handle, GWL_STYLE, Style);
  end;
end;  


来自:15687, 时间:2003-10-21 9:47:00, ID:2242840
请问DBTREEVIEW哪儿有免费的正版下载呀?  


来自:15687, 时间:2003-10-21 10:22:00, ID:2242974
To:不知道_0909
  能不能说一些具体怎么用的呀,我还是不懂。谢谢!
  怎样将数据添加到相应的节点我会,就是不知道怎样选择框,多谢指教!  


来自:chuanwang, 时间:2003-10-21 10:25:00, ID:2242980
帮帮忙!

请问DBTREEVIEW哪儿有免费的正版下载呀?

 


来自:delphiboy, 时间:2003-10-21 10:27:00, ID:2242991
定义一个指针到每个NODE上面
  police=^userdata
    userdata=record
         username:string;
         used:boolean ;
  end;
大概就这样,如果有权限这个node^.used=true;我这里作的权限控制不仅控制这个,还结合SQL SERVER和WINDOWS的安全机制完成,如ROLE,LOGUSER,USER,GROUP,等。好好看看SQL的安全机制吧。  


来自:tianjh007, 时间:2003-10-21 10:27:00, ID:2242992
以前作过,没代码了
原理其实就是画不同的图片
下边是超级猛料中的一段代码,我当时就是照这个去做的,你看看:

可以用变通的手法。
  TreeView有Images属性不是吗?自己做三张小图片:全选中、部分选中、不选状态(直接拍下CheckBox三种状态的图片在加工一下就可以了),然后在点击事件中根据具体情况设置TTreeNodes的ImageIndex就OK了。
  如果嫌麻烦的话就去Down一个控件,其实有些控件也是这样做的,界面上你是看不出来的.     :)
**************
Manan Patel <mpatel@siemens-hearing.com>
重载TreeView的CreateParams:
type
  TCheckBoxTreeView = class(TTreeView)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

procedure TCheckBoxTreeView.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style:=Params.Style or TVS_CHECKBOXES;
  { TVS_CHECKBOXES declared in CommCtrl }
end;

如果要Check这个CheckBox,可以用下面的代码:
function IsNodeChecked(Node :TTreeNode) :Boolean;
const
  TVIS_CHECKED = $2000;
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 SetNodeChecked(Node :TTreeNode; Checked :Boolean);
const
  TVIS_CHECKED = $2000;
var
  TvItem :TTVItem;
begin
  FillChar(TvItem, SizeOf(TvItem), 0);
  with TvItem do 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;
可以做成事件和封装成一个类:
private OldState :Boolean;

procedure Change(Node: TTreeNode); override;
begin
  inherited Change(Node);
  OldState := IsNodeChecked(Node);
end;

procedure Click; override;
var
  NewState :Boolean;
begin
  inherited Click;
  NewState := IsNodeChecked(Self.Selected);
  if NewState = OldState then Exit;
  if (NewState) and Assigned(OnNodeChecked) then OnNodeChecked()
  else if (not NewState) and Assigned(OnNodeUnChecked) then
OnNodeUnChecked()

// OnNodeChecked & OnNodeUnchecked will be events that you declare
end;

 


来自:不知道_0909, 时间:2003-10-21 10:29:00, ID:2242998
这是个例子
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ImgList, StdCtrls, Commctrl;//, ToolsUnit;


type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    ImageList1: TImageList;
    Button1: TButton;
    ListBox1: TListBox;
    procedure TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
const
  TVS_CHECKBOXES = $0100;
var
  Form1: TForm1;

implementation

{$R *.dfm}
procedure DOYNChecked(Node: TTreeNode; isChecked: Boolean);
var
  item:TTVItem;
begin
  item.mask:=TVIF_HANDLE;
  item.hItem:=Form1.TreeView1.Items[Node.AbsoluteIndex].ItemId;
  TreeView_GetItem(Form1.TreeView1.Handle,item);
  item.mask:=TVIF_HANDLE or TVIF_STATE;
  if not isChecked then
    item.state:= (item.state or $1000) and (not $2000)
  else
    item.state:= (item.state or $2000) and (not $1000);
  item.stateMask:=$ffffffff;
  TreeView_SetItem(Form1.TreeView1.Handle,item);
end;

procedure AllChildYNChecked(Node: TTreeNode; isChecked: Boolean);
var
  CurChild: TTreeNode;
begin
  if Node.HasChildren then
  begin
    CurChild:=Node.GetFirstChild;
    while CurChild <> nil do
    begin
      DOYNChecked(CurChild, isChecked);
      if CurChild.HasChildren then
      begin
        AllChildYNChecked(CurChild, isChecked);
      end;
      CurChild:=Node.getNextChild(CurChild);
    end;
  end;
end;{FreeDeleteNode}

function IsNodeChecked(Node :TTreeNode) :Boolean;
var
  item:TTVItem;
begin
  item.mask:=TVIF_HANDLE;
  item.hItem:=Form1.TreeView1.Items[Node.AbsoluteIndex].ItemId;
  TreeView_GetItem(Form1.TreeView1.Handle,item);
  if (item.state and $2000)=0 then
     Result := False
   else
     Result := True;
end;

function isBrotherAllChecked(Node: TTreeNode): Boolean;
var
  CurChild: TTreeNode;
  tmpBool: Boolean;
begin
  Node := Node.Parent;
  if Node.HasChildren then
  begin
    CurChild:=Node.GetFirstChild;
    while CurChild <> nil do
    begin
      tmpBool := IsNodeChecked(CurChild);
      if not tmpBool then
      begin
        Result := False;
        exit;
      end;
      CurChild:=Node.getNextChild(CurChild);
    end;
  end;
  Result := True;
end;

procedure SetParentChecked(Node: TTreeNode);
begin
  if Node.Parent <> nil then
  begin
    if isBrotherAllChecked(Node) then
      DOYNChecked(Node.Parent, True);
    SetParentChecked(Node.Parent);
  end;
end;

procedure SetParentNOChecked(Node: TTreeNode);
begin
  if Node.Parent <> nil then
  begin
    DOYNChecked(Node.Parent, False);
    SetParentNOChecked(Node.Parent);
  end;
end;

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
    else Style := Style or Value;
    SetWindowLong(Ctl.Handle, GWL_STYLE, Style);
  end;
end;


procedure TForm1.TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  HitTests: THitTests;
  tmpNode: TTreeNode;
begin
  HitTests := TreeView1.GetHitTestInfoAt(X, Y);
  if htOnStateIcon in HitTests then
  begin
    tmpNode := TreeView1.GetNodeAt(x, y);
    tmpNode.Selected := True;

    if IsNodeChecked(TreeView1.Selected) then
    begin
      SetParentChecked(TreeView1.Selected);
      AllChildYNChecked(TreeView1.Selected, true);
    end
    else
    begin
      SetParentNOChecked(TreeView1.Selected);
      AllChildYNChecked(TreeView1.Selected, False);
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetComCtlStyle(TreeView1,TVS_CHECKBOXES,True);
  TreeView1.Items[0].Expand(True)
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  aNode,Node: TTreeNode;
  vIndex, i, i1: Integer;
  s, s1:string;
begin
  i1 := 0;
  s := '';
  for vIndex := 0 to treeview1.Items.Count -1 do
  begin
    s := '';
    Node := treeview1.Items[vIndex];
    if Node.HasChildren then
      Continue
    else
    begin
      if IsNodeChecked(Node) then
      begin
        aNode := Node;
        for i:=0 to Node.Level do
        begin
          s :=  anode.Text+',' +s  ;
          aNode := aNode.Parent;
        end;
        listbox1.Items.Add(s);
      end
      else
        Continue;
    end;
  end;
end;

end.  


来自:lxm7805, 时间:2003-10-21 10:34:00, ID:2243012
呵呵,正我所要  


来自:江西的delphi, 时间:2003-10-21 10:49:00, ID:2243076
我的系统中的菜单权限就是这么做的,如果要源码及控件的话可以留下email,不过要意思一下哦(:
类金山毒ba  


来自:twos, 时间:2003-10-21 10:55:00, ID:2243102
VirtualTree可以轻松实现这个
可以使用这个控件看看  


来自:vivee, 时间:2003-10-21 11:30:00, ID:2243235
to 江西的delphi:
把你的菜单权限部分源码发给我,我可以给分的!!
分数乃身外之物:)

zyz_nj@21cn.com  


来自:江西的delphi, 时间:2003-10-21 11:40:00, ID:2243271
已发!  


来自:15687, 时间:2003-10-21 11:41:00, ID:2243276
to 江西的delphi:
  请将你的控件菜单源码发给我,高分相送。

jun_Cq@163.com  


来自:app2001, 时间:2003-10-21 11:54:00, ID:2243309
1stClass3000VCL的TfcTreeView控件能满足你的需要,我也是用这个控件做的一样的功能  


来自:江西的delphi, 时间:2003-10-21 12:26:00, ID:2243373
已发,是用1stClass3000VCL的TfcTreeView做的,全部手工控制!  


来自:15687, 时间:2003-10-21 13:01:00, ID:2243473
请问1stClass3000VCL的TfcTreeView那儿有得下载。谢谢!  


来自:dana, 时间:2003-10-21 14:31:00, ID:2243710
www.51delphi.com
可以下载dbtree,非常好用的控件啦.
posted @ 2008-04-09 12:20  蒋弢  阅读(279)  评论(0编辑  收藏  举报