我想在程序界面的左边放treeview,然后右边放一个能输入并显示文本的东西。然后我可以自己在左边的treeview上添加或是删除节点,还希望能给右边的输入文本的地方“赋值”。在使用时我只要单击某个节点就能在右边显示出相应的文本内容。
在程序启动时,应当能自动的load上一次使用时的节点信息和相应的右边的文本内容。个位高手,请告诉我右边的那个我该用什么?还有怎样保存节点信息和右边相应的文本内容,使下一次运行程序的时候,能自动load.

解决方案 »

  1.   

    这是我写的一段向treeview里添结点的看一看,
    procedure Tformproduct.datatotreeview;
    var treenodepinpai,treenodesort:Ttreenode;
    strbrand:string;//产品品牌
    begin
        if treeviewp_tree.Items.Count<2 then
        with adoqueryproduct do
        begin
           close;
           locktype:=ltOptimistic;
           sql.clear;
           sql.add('select distinct(sort),brand from product order by brand,sort');
           open;
           treeviewp_tree.Items.clear;
           treenodepinpai:=treeviewp_tree.Items.Add(nil,'产品');
           treeviewp_tree.Selected:=treenodepinpai;
           treenodepinpai.ImageIndex:=2;
           treenodepinpai.stateIndex:=2;
           treenodepinpai.SelectedIndex:=3;
           formP_add.ComboBoxbrand.Items.Clear;//置添加产品窗体里的comboboxbrand值。
           formp_add.comboboxsort.items.clear;
           strbrand:='';
           while not(eof) do
           begin
              if (uppercase(fieldbyname('brand').asstring)<>uppercase(strbrand)) then
              begin
                  strbrand:=fieldbyname('brand').asstring;
                  formp_add.ComboBoxbrand.Items.add(strbrand);
                  treenodepinpai:=treeviewp_tree.Items.add(nil,strbrand);
                  treenodepinpai.ImageIndex:=2;
                  treenodepinpai.stateIndex:=2;
                  treenodepinpai.SelectedIndex:=3;
              end ;
              formp_add.ComboBoxsort.Items.Add(fieldbyname('sort').asstring);
              treenodesort:=treeviewp_tree.Items.addchild(treenodepinpai,fieldbyname('sort').asstring);
              treenodesort.ImageIndex:=0;
              treenodesort.stateIndex:=0;
              treenodesort.SelectedIndex:=1;
              next;
           end;//while not(eof)   end;//with adoqueryproduct
    end;
    取结点的
    procedure TFormproduct.TreeViewP_treeClick(Sender: TObject);
    var treeviewnode,treenodep:Ttreenode;
    begin
        p_brand:='';
        p_sort:='';
        p_name:='';
        p_type:='';
        p_comment:='';
        treeviewnode:=treeviewp_tree.Selected;
        if treeviewP_tree.Selected.Level=0 then
        begin
            if treeviewnode.Text<>'产品' then
            begin
               p_brand:=treeviewnode.text;
            end;//if treeivewnode.text='产品'
        end else begin //else if treeviewP_tree.selected.level=0
            treenodep:=treeviewP_tree.Selected.Parent;
            p_brand:=treenodep.text;
            p_sort:=treeviewnode.text;
        end;//end if treeviewP_tree
        
    end;
      

  2.   

    这个问题很好办,调用数据库文件就可以了,右边放个MEMO显示文本。以前做过实现这种功能的程序,数据库文件需要添加几个字段,用做检验排放顺序以及父节点位置。
      

  3.   

    如果下次启动程序时要有上次编辑的结果,那么最好使用数据库,同时如果数据量比较小,也可以使用ini文件来存储,delphi封装了TIniFile类,提供了对ini文件的常规操作。
      

  4.   

    在程序启动时,应当能自动的load上一次使用时的节点信息和相应的右边的文本内容。??????????????????????
    与数据库连接,看看第一个回答你的程序,并不难!
      

  5.   

    一. 如何初始化一个TreeView? 
    弄一个窗口,放上一个TreeView和一个Button,分别取名为TV1和Btn1。如果需要 
    在每个节点前有个图,请在窗口上放上一个ImageList,取名为ImageList1,双击 
    它,加入六个图标。还要记得记得将TV1的Images属性改为ImageList1噢。双击按 
    钮Btn1,在里面填入以下代码,然后按F9运行,点击Btn1就可以看到效果了。 
    procedure TForm1.Btn1Click(Sender: TObject); 
    Const 
    MyDocDir = 'C:\My Documents'; 
    PersonDir = '3hSoft'; 
    Var 
    Var 
    I : Word; 
    SubNodeName : array [1..5] of ShortString; 
    RootNode, SubNode : TTreeNode; 
    P : PString; 
    begin 
    SubNodeName[1] := '便笺'; 
    SubNodeName[2] := '发件箱'; 
    SubNodeName[3] := '联系人'; 
    SubNodeName[4] := '任务'; 
    SubNodeName[5] := '日记'; 
    TV1.Items.Clear; 
    TV1.Items.BeginUpdate; 
    New(P); 
    P^ := MyDocDir + '\' + PersonDir; 
    RootNode := TV1.Items.AddObject(Nil, '个人文件夹', P); 
    // 此 Node 的图标已对 Images 属性中取第 0 个了。 
    For I := 1 to 5 do 
    begin 
    New(P); 
    P^ := MyDocDir + '\' + PersonDir + '\' + SubNodeName[I]; 
    SubNode := TV1.Items.AddChildObject(RootNode, SubNodeName[I], P) 


    // 如果不想使用图标的话请删除以下两行 
    SubNode.ImageIndex := I; 
    SubNode.SelectedIndex := I; 
    end; 
    TV1.Items.EndUpdate; 
    end; 
    二.在TreeView中如何设置选中结点 
    var 
    i:integer; {i为设置的选中结点的索引值} 
    begin 
    if i>treeview1.items.count then 
    treeview1.items[i].selected:=true; 
    或 
    treeview1.selected:=treeview1.items[i]; 
    三。设置TreeView结点的图形 
    1. 设置TreeView的images属性为已存在的images对象 
    treeview1.images:=imagelist1; 
    2. 在加入结点后执行: 
    var 
    anode:TTreeNode; 
    begein 
    anode:=Treeview1.add(nil,'item1'); 
    anode.imageindex:=0; {结点未选中时显示的图标} 
    anode.selectedindex:=1; {结点选中时显示的图标} 
    end 
    3. 如果结点图形在改变后未发生变化,可以执行: 
    treeview1.refresh; 
    四。如何批量处理TreeView结点 
    使用TreeView的items属性的BeginUpdate和EndUpdate方法,例: 
    TreeView1.items.BeginUpdate; 
    for i:=0 to TreeView1.items.count-1 do 
    begin 
    //将每个结点的文字改成为小写字母 
    TreeView1.items[i].text:=lowercase(TreeView1.items[i].text); 
    end; 
    TreeView1.items.EndUpdate; 五。实现TreeView结点拖拽的实例 
    下面的程序片段演示了如何实现拖拽treeview构件结点的例子 
    {鼠标按下时执行的语句} 
    procedure TForm1.Treeview1MouseDown(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
    begin 
    {判断左键按下并且鼠标点在一个结点上开始实现拖拽} 
    if ( Button = mbLeft ) and 
    ( htOnItem in Treeview1.GetHitTestInfoAt( X, Y ) ) then 
    begin 
    Treeview1.BeginDrag( False ); 
    end; 
    end; 
    {鼠标拖动执行语句} 
    procedure TForm1.Treeview1DragOver( Sender, Source: TObject; 
    X, Y: Integer; State: TDragState; var Accept: Boolean); 
    var 
    Node : TTreeNode; 
    begin 
    if Source = Treeview1 then 
    begin 
    Node := Treeview1.GetNodeAt( X, Y ); {取当前结点} 
    if Node <> nil then {当前结点不为空才能实现拖拽,accept:=true} 
    Accept := true; 
    end; 
    end; 
    {鼠标释放时执行的语句} 
    procedure TForm1.Treeview1DragDrop( Sender, Source: TObject; 
    X, Y : Integer ); 
    var 
    TempNode : TTreeNode; 
    AttachMode : TNodeAttachMode; 
    begin 
    if Treeview1.Selected = nil then 
    Exit; 
    AttachMode := naAddChild; {设置结点移动模式,设移动结点为子结点} 
    { 注意在这里存在一个bug,当移动结点时,如果目标结点没有子结点,} 
    { 则加入的新的子结点会失败,所以先在当前目标结点的下面 } 
    { 加入一个临时子结点,移动完毕后,再将临时结点删除 } 
    Treeview1.Items.BeginUpdate; 
    try 
    TempNode := Treeview1.Items.AddChild( Treeview1.DropTarget, 
    'Temp' ); 
    try 
    { 移动选中的结点到目标结点 } 
    Treeview1.Selected.MoveTo( Treeview1.DropTarget, AttachMode ); 
    finally 
    TempNode.Free; { 不要忘了释放临时结点 } 
    end; 
    finally 
    Treeview1.Items.EndUpdate; 
    end; 
    end; 
      

  6.   

    一. 如何初始化一个TreeView? 
    弄一个窗口,放上一个TreeView和一个Button,分别取名为TV1和Btn1。如果需要 
    在每个节点前有个图,请在窗口上放上一个ImageList,取名为ImageList1,双击 
    它,加入六个图标。还要记得记得将TV1的Images属性改为ImageList1噢。双击按 
    钮Btn1,在里面填入以下代码,然后按F9运行,点击Btn1就可以看到效果了。 
    procedure TForm1.Btn1Click(Sender: TObject); 
    Const 
    MyDocDir = 'C:\My Documents'; 
    PersonDir = '3hSoft'; 
    Var 
    Var 
    I : Word; 
    SubNodeName : array [1..5] of ShortString; 
    RootNode, SubNode : TTreeNode; 
    P : PString; 
    begin 
    SubNodeName[1] := '便笺'; 
    SubNodeName[2] := '发件箱'; 
    SubNodeName[3] := '联系人'; 
    SubNodeName[4] := '任务'; 
    SubNodeName[5] := '日记'; 
    TV1.Items.Clear; 
    TV1.Items.BeginUpdate; 
    New(P); 
    P^ := MyDocDir + '\' + PersonDir; 
    RootNode := TV1.Items.AddObject(Nil, '个人文件夹', P); 
    // 此 Node 的图标已对 Images 属性中取第 0 个了。 
    For I := 1 to 5 do 
    begin 
    New(P); 
    P^ := MyDocDir + '\' + PersonDir + '\' + SubNodeName[I]; 
    SubNode := TV1.Items.AddChildObject(RootNode, SubNodeName[I], P) 


    // 如果不想使用图标的话请删除以下两行 
    SubNode.ImageIndex := I; 
    SubNode.SelectedIndex := I; 
    end; 
    TV1.Items.EndUpdate; 
    end; 
    二.在TreeView中如何设置选中结点 
    var 
    i:integer; {i为设置的选中结点的索引值} 
    begin 
    if i>treeview1.items.count then 
    treeview1.items[i].selected:=true; 
    或 
    treeview1.selected:=treeview1.items[i]; 
    三。设置TreeView结点的图形 
    1. 设置TreeView的images属性为已存在的images对象 
    treeview1.images:=imagelist1; 
    2. 在加入结点后执行: 
    var 
    anode:TTreeNode; 
    begein 
    anode:=Treeview1.add(nil,'item1'); 
    anode.imageindex:=0; {结点未选中时显示的图标} 
    anode.selectedindex:=1; {结点选中时显示的图标} 
    end 
    3. 如果结点图形在改变后未发生变化,可以执行: 
    treeview1.refresh; 
    四。如何批量处理TreeView结点 
    使用TreeView的items属性的BeginUpdate和EndUpdate方法,例: 
    TreeView1.items.BeginUpdate; 
    for i:=0 to TreeView1.items.count-1 do 
    begin 
    //将每个结点的文字改成为小写字母 
    TreeView1.items[i].text:=lowercase(TreeView1.items[i].text); 
    end; 
    TreeView1.items.EndUpdate; 五。实现TreeView结点拖拽的实例 
    下面的程序片段演示了如何实现拖拽treeview构件结点的例子 
    {鼠标按下时执行的语句} 
    procedure TForm1.Treeview1MouseDown(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
    begin 
    {判断左键按下并且鼠标点在一个结点上开始实现拖拽} 
    if ( Button = mbLeft ) and 
    ( htOnItem in Treeview1.GetHitTestInfoAt( X, Y ) ) then 
    begin 
    Treeview1.BeginDrag( False ); 
    end; 
    end; 
    {鼠标拖动执行语句} 
    procedure TForm1.Treeview1DragOver( Sender, Source: TObject; 
    X, Y: Integer; State: TDragState; var Accept: Boolean); 
    var 
    Node : TTreeNode; 
    begin 
    if Source = Treeview1 then 
    begin 
    Node := Treeview1.GetNodeAt( X, Y ); {取当前结点} 
    if Node <> nil then {当前结点不为空才能实现拖拽,accept:=true} 
    Accept := true; 
    end; 
    end; 
    {鼠标释放时执行的语句} 
    procedure TForm1.Treeview1DragDrop( Sender, Source: TObject; 
    X, Y : Integer ); 
    var 
    TempNode : TTreeNode; 
    AttachMode : TNodeAttachMode; 
    begin 
    if Treeview1.Selected = nil then 
    Exit; 
    AttachMode := naAddChild; {设置结点移动模式,设移动结点为子结点} 
    { 注意在这里存在一个bug,当移动结点时,如果目标结点没有子结点,} 
    { 则加入的新的子结点会失败,所以先在当前目标结点的下面 } 
    { 加入一个临时子结点,移动完毕后,再将临时结点删除 } 
    Treeview1.Items.BeginUpdate; 
    try 
    TempNode := Treeview1.Items.AddChild( Treeview1.DropTarget, 
    'Temp' ); 
    try 
    { 移动选中的结点到目标结点 } 
    Treeview1.Selected.MoveTo( Treeview1.DropTarget, AttachMode ); 
    finally 
    TempNode.Free; { 不要忘了释放临时结点 } 
    end; 
    finally 
    Treeview1.Items.EndUpdate; 
    end; 
    end; 
      

  7.   

    你说的功能用treeview1.selected.text就可以赋值了
    比如treeview1.Selected.Text :=edit2.Text ;
    至于调用上次的信息,数据库很好实现
    或者你把这些信息保存出来比如写到文本里
      

  8.   

    》》 9igogo(就爱狗狗) 
      能不能稍微详细的讲一下用数据库的实现,因为数据量不是很小。
      

  9.   

    要实现4个功能,一是启动时载入上次退出时的界面,二是点击左边节点右边显示相应的文本,三是在TreeView上进行添加删除操作,四是在右边编辑文本并保存。下面逐一给出代码:
      

  10.   

    首先,新建一个数据表,含有4个字段,分别为ABSID,PARID,LAST,CONTENT,其中ABSID为绝对节点数,一个TreeView完全展开后从上到下绝对节点数依次为0,1,2,3,……;PARID为父节点的绝对节点数;LAST为判断是否为上次退出时的最后显示内容,如果是则赋值为1,否则为0;CONTENT即为点击节点后显示的内容。
      

  11.   

    >>>marshalidle() :
      不是说又逐一代码吗?
      

  12.   

    Rebeca,不要这么急啊,程序是我以前写的,现在在看代码,有的都快忘记了,修改了才能贴出来啊。再说我写的比这个复杂,要简单化啊。
    下面给出第一步:
    假设数据表存为111.db,和程序放在同一目录,程序中放TreeView1,memo1,table1,其中table1
    的tablename属性为111.db,启动时载入上次退出时的界面的代码如下:
    procedure TForm1.FormCreate(Sender: TObject);
    var
      parentnode: TTreeNode;
    begin
        table1.Active:=false;
        table1.Active:=true;
        with table1 do
         begin
          while not Eof do
           begin
            if table1.Fields.Fields[1].AsInteger<>-1 then
             begin
              parentnode:=treeview1.Items.Item[table1.Fields.Fields[1].AsInteger];
              Treeview1.Items.AddChild(parentnode,table1.Fields.Fields[0].AsString);
             end
            else Treeview1.Items.Add(nil,table1.Fields.Fields[0].AsString);
            next;
           end;
         end;
        table1.Active:=false;
    end;
      

  13.   

    举个例子,若111.db中内容为
    ABSID  PARID  LAST CONTENT
      0     -1     0     00
      1      0     0     11
      2      0     1     22
      3      2     0     33
      4     -1     0     44
      5     -1     0     55
      6      5     0     66
    则说明上次关闭时点击的是第3个节点。程序启动时载入所有节点,并将第3个节点的文本“22”显示在右边的文本框里。刚才给的代码只是显示treeview的,还没加显示文本的,都是你催的,没写完。你先试试这第一步。
      

  14.   

    好了,给出第一步的完整代码:
    procedure TForm1.FormCreate(Sender: TObject);
    var
      parentnode: TTreeNode;
      i:integer;
    begin
        table1.Active:=false;
        table1.Active:=true;
        with table1 do
         begin
          while not Eof do
           begin
            if table1.Fields.Fields[1].AsInteger<>-1 then
             begin
              parentnode:=treeview1.Items.Item[table1.Fields.Fields[1].AsInteger];
              Treeview1.Items.AddChild(parentnode,table1.Fields.Fields[0].AsString);
             end
            else Treeview1.Items.Add(nil,table1.Fields.Fields[0].AsString);
            if table1.Fields.Fields[2].AsInteger=1 then
               begin
                 memo1.Text:=table1.Fields.Fields[3].AsString;
                 i:=table1.Fields.Fields[0].AsInteger;
               end;
            next;
           end;
         end;
        table1.Active:=false;
        treeview1.Items.Item[i].Selected:=true;
    end;
      

  15.   

    第二步,点击左边节点右边显示相应的文本,代码很简单:
    procedure TForm1.TreeView1Click(Sender: TObject);
    begin
       if treeview1.Selected.AbsoluteIndex<>-1 then
         begin
          table1.Active:=false;
          table1.Active:=true;
          table1.RecNo:=treeview1.Selected.AbsoluteIndex+1;
          memo1.Text:=table1.Fields.Fields[3].AsString;
          table1.Active:=false;
         end;
    end;
      

  16.   

    第二步的代码需要改一下,
    procedure TForm1.TreeView1Click(Sender: TObject);
    begin
       try
          table1.Active:=false;
          table1.Active:=true;
          table1.RecNo:=treeview1.Selected.AbsoluteIndex+1;
          memo1.Text:=table1.Fields.Fields[3].AsString;
          table1.Active:=false;
       except
       end;
    end;
      

  17.   

    接着来第3步,在窗口中加入一个popupmenu,名字为PopupMenu1,菜单为添加和删除,TreeView1的PopupMenu属性设为PopupMenu1,这样程序运行后右键点击treeview会弹出添加删除窗口,具体添加删除代码稍后再贴出来,还得提炼。
      

  18.   

    >>marshalidle()
      大好人啊:)期待着你将要贴出来的内容!
      完成后,另开帖子再给你分:)
      

  19.   

    看了一下,后面的代码实在是太复杂了,有很多的变量和步骤,由于涉及到商业秘密又不能全部贴出来,可是要我去提取估计也不是几小时能完成的事,很多东西是这里不需要的。这样吧,我大概把后面的思路说一下,因为有了前面的介绍估计还是比较好做的:
    点击添加,将此时所点击的节点的绝对节点数赋值给一个变量a,并统计这个节点的所有子节点数目,赋值给另一个变量b,并且弹出一个新的窗口,要求输入添加的内容。点确定以后,在111.db中第a+b+2行添加一行数据(因为a是从0开始增加的),这个所添加的数据内容是:ABSID为a+b+1,PARID为a,LAST为1,CONTENT为新窗口中输入的内容。另外,需要把以前LAST为1的数据赋值为0,并且ABSID大于a+b的数据的ABSID都加1。好象就这么多,可能还有的没写上,慢慢去琢磨了。删除原理和这个差不多,反正主要就是围绕着数据表的ABSID和PARID字段进行修改。LAST和CONTENT一般倒不用操心。第4步在右边修改文本并保存更加容易了,不用我来多说大家都知道怎么做的。
      

  20.   

    哦,还有就是添加完和删除完和修改完后左边的tree也要变的,通过代码按照LOAD时的原理做就OK了。
    这个程序实现的原理其实很简单,就是操作有点复杂,一步都不能想错,梢有差错,出了问题连自己都很难找出问题所在。
    Rebeca,如果你在周末之前还没搞定,可以给我来信,[email protected],周末我再抽取时间帮你一把了。不过你不能偷懒,这几天还是得自己思考,自己解决最好。
    最后问一个问题,这个分数用来做什么的?没有分有问题我也会帮忙的,大家都会有困难的。
      

  21.   

    >> marshalidle()
     真的很感谢你,我会努力的.
    因为以前从来没做过这些东西,所以一定还会有需要你帮忙的地方,先说声谢谢了.
      

  22.   

    还想问一下
      如果我想再单击一个节点后,在右边的memo中显示出相应的111.db中的content的内容?怎样把content取出来?
      

  23.   

    procedure TForm1.TreeView1Click(Sender: TObject);
    begin
       try
          table1.Active:=false;
          table1.Active:=true;
          table1.RecNo:=treeview1.Selected.AbsoluteIndex+1;
          memo1.Text:=table1.Fields.Fields[3].AsString;
          table1.Active:=false;
       except
       end;
    end;
    上面不是给了吗?第2步的代码。以后有问题来信问我吧,不可能每天都上这来看贴的。