我用treeview和listview做了一个树型数据表的显示,譬如我在treeview上选择一个treenode(节点)在listview上就会显示出属于这个节点的子节点,做法就是用该treenode的名字查询数据库,把属于该节点的子节点数据用listview显示出来。但有一个问题就是,如果treeview上存在两个相同名字的treenode时,这是就查询不出来了,但如果在每一个treenode上都记录一个id值,对应数据表的ID字段,在查询时用id来查询而不是用treenode的名字,这样就算存在两个相同名字的treenode时都没所谓了,那应该怎样来记录这个id的值呢?在线等待!

解决方案 »

  1.   

    可以自己定义一个新的类
    也可以就利用treenode.stateindex
    在创建treeview的时候,将stateindex一起赋值
      

  2.   

    treenode有data,的属性。你可以在生成树的同时把data,text的值附个每个treenode就可以了。
      

  3.   

    首先定义一个类型:
    Type
      PMyCode = ^TMyCode;
      TMyCode = Record
        vName: String; //名称
        vCode: String; //编码
      End;var
      DataRec1:PMyCode;  new(DataRec1);
      DataRec1^.vCode := trim(FindField(vCode).AsString);
      DataRec1^.vName := trim(FindField(vName).AsString);
    {
    .....
    }
      TreeView1.Items.AddChildObject(Mynode, '名字', DataRec1);当选中时(OnChange):
    if TreeView1.Selected<>nil then
    ShowMessage(PMyRec(TreeView1.Selected.Data)^.vCode);
      

  4.   

    以上这个办法也许不错,但delphi文档中所说的,new(datarec1)所占的内存在treeview被free之后,并不会自动回收,所以请问在何时何处以什么方式回收datarec1所占的内存会比较好呢?
      

  5.   

    请问个位高手,我也想创建一个自已的Tmytreenode类,如下:
    type Tmytreenode=class(Ttreenode)
        vname:string;
        vcode:string;
    end;
    但如何用自已的这个Tmytreenode形成treeview呢?
      

  6.   

    直接把id存在TreeNode的data属性中,用时直接取出来Node.Data = pointer(id);
    id = integer(Node.Data);
      

  7.   

    enlightenment(冰封超人),期待你的贴子!!!!
      

  8.   

    你可以这样做,在进行初始化时建立一个字符串列表,用来存ID值。
    这样的话,再一次用到时,便可以直接到字符串列表中找了。
    procedure Tfrm_main.RefreshCata; //刷新视图
    var
     node:TTreeNode;
     str,id:String;
    begin
    list_bh.Clear;
    list_cata.Items.Clear;
    sql_cata.SQLQuery('select bh,cata_name,cata_xm_count,cata_memo from cata');
     id:=sql_cata.GetValueByIndex(0);
        if id<>'' then
        sql_xm.SQLQuery('select * from xm where xm_cata_bh='+id);
        id:=sql_xm.GetValueByIndex(0);
        sql_jdb.SQLQuery('select * from jdb where jdb_xm_bh='+id);
    while Not sql_cata.Eof  do
      begin
        str:=sql_cata.GetValueByIndex(1);
        node:=list_cata.Items.Add(nil,str);
        str:=sql_cata.GetValueByIndex(0);
        list_bh.add(str);//注意!这里记录所需要的ID值。
        sql_cata.Next;
      end;
    sql_cata.Close;
    end;
      

  9.   

    ■ TTreeView组件的一点使用技巧(虚拟节点、对象索引等)
    对于使用标准的OO设计方法,TTreeView提供了AddItem(‘string’,Point)方法,Point可以用于存储对象的指针。在需要根据节点引用对象时,可以使用RTTI的is、as来取得对象(也可以用类标识符强制类型转换,但不安全);
    对于设计跟数据库相关的程序,还有InfoPower的TfcTreeView组件可以使用,TfcTreeView的节点TfcTreeNode除了“Text”外带有两个扩展字符串属性“StringData”、“StringData2”,我自己经常采用的做法是,“Text”属性存储显示标题,“StringData”属性存储记录的ID,“StringData2”属性存储记录的类型(先要在程序中将每种记录类型用不重复的常量进行标记),这样在寻找节点对应记录时将带来巨大方便。但TfcTreeView的缺点有:1、当图标节点多时,组件图象更新很慢,包括拖动条响应;2、在更新组件前后需要依次调用BeginUpdate与EndUpdate方法,否则很可能导致屏幕显示出问题;
    为了树型视图加载的快速性,普遍采用的方法是——根据需要加载子节点,首先为未确认的是否含有子节点的对象设置一个虚拟子节点(所谓虚拟节点是指一个在软件中被作了标记的但无其它实际意义的节点),并保持收缩状态(未展开),当用户点击要展开节点时,在节点的OnExpanding事件中添加处理函数,首先判断是否只包含虚拟节点,如果是则先删除虚拟节点,再将其所包含的真正子节点加载(如果无子节点,则被选节点自然显示为叶节点)。
    对于上面的一般通则,尤其针对于那些展开节点需要花较长时间的情况比较适用,如WINDOWS的“网上邻居”节点部分,“SQL SERVER”中展开数据库的节点等等。
    这种做法还有一个遗留问题,就是——如果用户没有选择具体节点,那么所有边缘节点就都处于收缩状态且很可能这些边缘节点下并不包含任何子节点,好象不如WINDOWS资源管理器中本地目录树那样直观。其实,处理这个问题的办法很简单,就是在展开某层(如第一层)节点时的事件处理函数中添加下层(就是第二层)节点的虚拟节点处理事件。但这种做法需要考虑程序响应时间的问题,如果此过程消耗时间太多,会对用户的操作性能有很大影响。
    另外补充,还可以在以上处理过程中添加消息处理函数Application.ProcessMessage以响应用户操作,但需要考虑这样可能带来的临界资源竞争,程序绘写事件冲突等问题,总之,如果要这样做,你必须清楚的知道自己在做什么。■ TListView关于对象指针需要注意的问题
    看了上面关于TTreeView第一段的描述,很自然的会希望在TListView中也能够使用对象指针。不幸的是,我多次的经验告诉我,TListView中TListItem所包含的指针属性不如TTreeView中来得可靠,到底是什么原因还不得而知(我认为是Borland自己的问题,不能太迷信,Borland的一些组件确实有问题,譬如我在写《物业I》系统时发现的TCombBoxEx的文本信息存取出错问题等!)
    至于替代的办法是,在TListItem的SubItems最后添加多几条自定义的不在Columns列显示的信息。
      

  10.   

    顺便提下,上面其他人提到的扩展TTreeNode类属性的方法是可行的,但要做好就最好是对TTreeView类整个进行扩展,包括TTreeNodes(从TCollection派生)、TTreeNode(从TCollectionItem派生)等类,但编码工作甚是烦琐。
        出于时间的考虑,还是推荐使用InfoPower的TfcTreeView组件(当然,选用组件时也要注意组件的稳定性、性能等指标)。
      

  11.   

    最好用dx系列的组件,里面有一个dxDBTreeView可以用一个表将它保存起来,然后你就可以用它的属性进行操作,很方便的,我开发了一个POS系统也用它,效果很好,而且它可以无限分类下去。
    如果要的话,发封邮件到.cn