在加载二级节点时,从数据库中查询用户名,想能实现这样的功能,在查询用户名的同时判断该用户是否为销户状态,如果是,则将该节点的颜色设为红色,以下是加载二级节点代码:
if treeview1.Selected.HasChildren then//如果当前选中的节点有子节点,则不再加载
   abort
else
begin
 while not  ado_add.Eof do
 begin
   node_bill:=treeview1.Items.AddChild(treeview1.Selected,ado_add.fieldbyname('khmc').AsString);
   if ado_add.FieldByName('xiaohu').AsBoolean=true then
      xiaohu_flag:=true;
   ado_add.Next;
 end;
end;
然后在 customerdrawitem 事件中进行判断:
 if xiaohu_flag=true then
    treeview1.canvas.font.color:=clred;
这样一来所有的节点都变成了红色,如果用node.level:=clred 则所有的二级节点都变成红色,我只要符合条件的用户才将它的颜色改变,有没有什么方法可以做到啊?在网上找了很多都没达到效果,郁闷中~~~

解决方案 »

  1.   

    我觉得可以在树结点前显示不同的图标,来表示是否销户状态比较好,
    设计node_bill的imageindex即可
      

  2.   

    CustomerDraw的代码应该没有问题啊。
      

  3.   

    你的语句是没有问题的, 但你的问题出在 if xiaohu_flag=true then建议你这样改改看:TNodeData = paceked record
      xiaohu_flag: Boolean;
      ......其他信息
    end;
    PTNodeData = ^TNodedata;所有的节点的Data都是此记录类型;
    将下面的语句更改:
    var
      NodeData = PTNodeData;
    begin
    ......
    if ado_add.FieldByName('xiaohu').AsBoolean=true then
          xiaohu_flag:=true;更改为
    .....
    if ado_add.FieldByName('xiaohu').AsBoolean=true then
          NodeData.xiaohu_flag:=true;
    else
         NodeData.xiaohu_flag:=False;..............
    if xiaohu_flag=true then
        treeview1.canvas.font.color:=clred;改为
    ..........
    if PTNodeData(Node.Data).xiaohu_flag=true then
        treeview1.canvas.font.color:=clred;
      

  4.   

    漏了一点,在生成节点时还要加上

    Node.Data = @NodeData;
      

  5.   

    PTNodeData = ^TNodedata; //指针?
     Node.Data = @NodeData; //这两句还不太明白是什么作用?
    if PTNodeData(Node.Data).xiaohu_flag=true then   //这边会有地址引用错误,窗体一显示时就会执行这边的代码
      

  6.   

    给你一个测试代码,还有什么问题欢迎随时提出(这段代码是偶数节点的字体颜色为红色)TNodeData = packed record
        xiaohu_flag: Boolean;
      end;
      PTNodeData = ^TNodedata;
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        ImageList1: TImageList;
        Button1: TButton;
        procedure TreeView1CustomDrawItem(Sender: TCustomTreeView;
          Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
      Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      if PTNodeData(Node.Data).xiaohu_flag  then
       Treeview1.Canvas.Font.Color := clred;
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      Idx: Integer;
      NodeData: array [0..1000] of PTNodeData;
      Node: TTreeNode;
    begin
      for Idx := 0 to 10 do
      begin
        New(NodeData[Idx]);
        Node := Treeview1.Items.AddChild(nil, '');
        if Idx mod 2 = 0 then
          NodeData[Idx].xiaohu_flag := True
        else
          NodeData[Idx].xiaohu_flag := False;
        Node.Data := NodeData[Idx];
        Node.Text := 'Node'+IntToStr(Idx);
        Node.ImageIndex := 0;
      end;
    end;
      

  7.   

    晕了,还是地址引用错误:
    我的代码:(ondbclick) treeview1
       Node.Data := @NodeData;
       if treeview1.Selected.HasChildren then      //如果当前选中的节点有子节点,则不再加载
          abort
       else
       begin
         while not  ado_add.Eof do
         begin
            node_bill:=treeview1.Items.AddChild(treeview1.Selected,ado_add.fieldbyname('khmc').AsString);
            if ado_add.FieldByName('xiaohu').AsBoolean=true then
               NodeData.xiaohu_flag:=true
            else
               NodeData.xiaohu_flag:=False;
            ado_add.Next;
         end;
       end;
    后面的判断代码是一样的,可就是地址引用出错~~~不懂哪错了啊~
    还是这两句不懂什么作用~~~
    PTNodeData = ^TNodedata; //指针?
     Node.Data = @NodeData;  //这两句还不太明白是什么作用?
    麻烦你了`~~~~
      

  8.   

    全心全意为人民服务。呵呵呵呵procedure TForm1.TreeView1Click(Sender: TObject);
    var
      Idx: Integer;
      NodeData: array [0..1000] of PTNodeData;
      Node_Bill: TTreeNode;
    begin
      if treeview1.Selected.HasChildren then      //如果当前选中的节点有子节点,则不再加载
          abort
      else
      begin
        for Idx := 0 to 10 do
        begin
          New(NodeData[Idx]);
          node_bill:=treeview1.Items.AddChild(treeview1.Selected, '');
          if Idx mod 2 = 0 then
             NodeData[Idx].xiaohu_flag:=true
          else
             NodeData[Idx].xiaohu_flag:=False;
          Node_Bill.Data := NodeData[Idx];
          Node_Bill.Text := 'Node'+IntToStr(Idx);
          Node_Bill.ImageIndex := 0;
        end;
      end;
    end;
      

  9.   

    去看看效果吧, 不过你应该在加上一条就是当Node的LEVEL判断,否则它会无限LEVEL的加节点
      

  10.   

    晕哪,还是那个错误~~~
    procedure TE_khzl_changeF.TreeView1CustomDrawItem(Sender: TCustomTreeView;
      Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      if PTNodeData(Node.Data).xiaohu_flag  then
       Treeview1.Canvas.Font.Color := clred;
    end;
    这段代码怎么在窗体一创建时就会执行的啊?
      

  11.   

    顶sanmaotuo(老冯) ~~~楼上说的,>>这段代码怎么在窗体一创建时就会执行的啊?原因可能是,你的treeview,在设计时就在添加了一些结点,对吧,这样的话,窗体在create时,会在创建treeview时,就会执行CustomDrawItem事件,因此,可按你上边的代码改一下;procedure TE_khzl_changeF.TreeView1CustomDrawItem(Sender: TCustomTreeView;
      Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      if Node.HasChildren  then //添加这个判断
        exit;  if PTNodeData(Node.Data).xiaohu_flag  then
         Treeview1.Canvas.Font.Color := clred;
    end;嘿嘿,我乱猜的~~~
      

  12.   

    楼上好像也不行,如果,来不及添加二级结点,还是会出错,procedure TE_khzl_changeF.TreeView1CustomDrawItem(Sender: TCustomTreeView;
      Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      if (Node.level =0)  then //这样判断试试,反正一级结点就退出
        exit;  if PTNodeData(Node.Data).xiaohu_flag  then
         Treeview1.Canvas.Font.Color := clred;
    end;
      

  13.   

    在加入一级节点是就要把Node.data := PTNodeData, 否则肯定稀里哗啦啦啦我在第一段就已经说明了啊,同志们。呵呵呵呵
      

  14.   

    呵,谢谢两位,我正烦着呢~我在窗体显示时加载了一级节点,双击时加载二级节点,反正到了那边就会出错,我也试着用  do2008  的方法进行判断,如果没有加载二级节点时就退出,窗体显示时没错,可是当双击时还是会有那个错误~~~~~~我的一级节点是在窗体显示时加载的
    Node.data := PTNodeData; 这个是写在加载一级节点的地方么?会有错误~~
    [Error] E_khzl_change.pas(271): '(' expected but ';' found
      

  15.   

    我测试过了你的啊,如果不加载两级节点,只加载一级节点的话没问题(按钮),然后我在窗体显示时加载一级节点,在双击事件里加载二级节点后就会有问题了,这要怎么改啊?
    ----------------------------------------------
    在加入一级节点是就要把Node.data := PTNodeData,
    ----------------------------------------------
     可是这个写在加载一级节点时会出错.
    真是太麻烦你了~呵~
      

  16.   

    无语了。世界需要热心肠type
      TNodeData = packed record
        xiaohu_flag: Boolean;
      end;
      PTNodeData = ^TNodedata;
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        ImageList1: TImageList;
        Button1: TButton;
        procedure TreeView1CustomDrawItem(Sender: TCustomTreeView;
          Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
        procedure Button1Click(Sender: TObject);
        procedure TreeView1Click(Sender: TObject);
      private
        { Private declarations }
      public
      end;var
      Form1: TForm1;implementationuses
      Clipbrd;{$R *.dfm}procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
      Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      if PTNodeData(Node.Data).xiaohu_flag  then
       Treeview1.Canvas.Font.Color := clred;
    end;procedure TForm1.Button1Click(Sender: TObject);   //增加一级节点
    var
      Idx: Integer;
      NodeData: array [0..1000] of PTNodeData;
      Node: TTreeNode;
    begin
      for Idx := 0 to 10 do
      begin
        New(NodeData[Idx]);
        Node := Treeview1.Items.AddChild(nil, '');
        if Idx mod 2 = 0 then
          NodeData[Idx].xiaohu_flag := True
        else
          NodeData[Idx].xiaohu_flag := False;
        Node.Data := NodeData[Idx];
        Node.Text := 'Node'+IntToStr(Idx);
        Node.ImageIndex := 0;
      end;
    end;procedure TForm1.TreeView1Click(Sender: TObject);   //增加二级节点
    var
      Idx: Integer;
      NodeData: array [0..1000] of PTNodeData;
      Node_Bill: TTreeNode;
    begin
      if treeview1.Selected.HasChildren then
          abort
      else
      begin
        for Idx := 0 to 10 do
        begin
          New(NodeData[Idx]);
          node_bill:=treeview1.Items.AddChild(treeview1.Selected, '');
          if Idx mod 2 = 0 then
             NodeData[Idx].xiaohu_flag:=true
          else
             NodeData[Idx].xiaohu_flag:=False;
          Node_Bill.Data := NodeData[Idx];
          Node_Bill.Text := 'Node'+IntToStr(Idx);
          Node_Bill.ImageIndex := 0;
        end;
      end;
    end;
      

  17.   

    在Click最前面加上
    if Treeview1.Selected <> nil then
      

  18.   

    问题解决了,晕啊,New(NodeData[Idx]);这个只能在加载一级节点时写,加载二级节点时不能写
      New(NodeData[Idx]);你两次加载都写了,我测试时好像不行哦~
      

  19.   

    晕哪,我搞了两个小时了~可是还有问题啊,第一次双击打开二级节点时没问题,如果再点一下其它的节点,那它的颜色马上就会变掉,是不是跟我的树的onchange事件有关啊?这里我只是查找相应的用户记录出来的~
      

  20.   

    你在ONChange写了些什么东东?
      

  21.   

    不关onchange里面的事了,我把里面的代码都去掉了还是一样的,如果再次点击到那个改变了颜色的节点,颜色就会变为原来的,再次展开一级节点也是一样的颜色会变掉~~~~
      

  22.   

    呵,不敢啊,我觉得奇怪啊,我另外写的一个都不会这样的,真晕~一级节点是区域,二级节点是用户名,我把这两个都给你看下:
    窗体的 onshow 事件:
       ado_add.SQL.Clear;
       ado_add.SQL.Text:='select distinct pqmc from pqzl';
       ado_add.Open;
       for i:=0 to ado_add.RecordCount-1 do
       begin
          New(NodeData[i]);
          dbcombobox2.Items.Add(ado_add.fieldbyname('pqmc').AsString);
          node:=treeview1.Items.Add(nil,ado_add.fieldbyname('pqmc').AsString);
          ado_add.Next;
       end;
    树的 ondbclick事件:
       if treeview1.Selected.HasChildren then      //如果当前选中的节点有子节点,则不再加载
          abort
       else
       begin
         for idx:=0 to ado_add.RecordCount-1 do
         begin
            node:=treeview1.Items.AddChild(treeview1.Selected,ado_add.fieldbyname('khmc').AsString);
            if ado_add.FieldByName('xiaohu').AsBoolean=true then
               NodeData[Idx].xiaohu_flag :=true
            else
               NodeData[Idx].xiaohu_flag :=False;
            Node.Data := NodeData[Idx];
            ado_add.Next;
         end;
       end;
    你帮我看下哪里有问题-_-~~
      

  23.   

    你在哪里定义的NodeData??估计是这个问题啊
      

  24.   

    在public处啊,可是另一个测试程序也是定义在那边的,都没问题~
      

  25.   

    呵呵, 你太粗心了啊: 你看看你在ONSHOW中没有给Node.data赋值啊。node:=treeview1.Items.Add(nil,ado_add.fieldbyname('pqmc').AsString);加
    ......
    nodedata[Idx].xiaohu_flag := False;
    Node.Data := NodeData[Idx];
    ......
    ado_add.Next;
      

  26.   

    怎么能够定义在PUBLIC呢》?Node.data 是Pointer啊!!同志
      

  27.   

    晕~在加载二级节点时添加一句就好了:New(NodeData[idx]);
    可是怎么测试程序都不要这样写却可以达到效果的啊,还有哦,再问你一下,nodedata要定义在哪里呀?这是测试程序:
    procedure TForm1.Button2Click(Sender: TObject);//一级
    var
       i:integer;
    begin
      for i:=0 to 20 do
      begin
         New(NodeData[i]);
         node:=treeview1.Items.Add(nil,'1221');
      end;
    end;
    procedure TForm1.TreeView1DblClick(Sender: TObject);//二级
    var
      Idx: Integer;
    begin
      if treeview1.Selected.HasChildren then
         abort
      else
      begin
        for Idx := 0 to 10 do
        begin
          Node := Treeview1.Items.AddChild(treeview1.Selected,'123' );
          if Idx mod 2 = 0 then
            NodeData[Idx].xiaohu_flag := True
          else
            NodeData[Idx].xiaohu_flag := False;
          Node.Data := NodeData[Idx];
      end;
      end;
    end;
      

  28.   

    NODE和nodedata的作用域一定只能在某个方法内。
      

  29.   

    不论哪一级他的NODE的Data都要赋值。 累啊累啊。冒昧问一下,您是哪里的?
      

  30.   

    程序不会引用其它地方的同名的指针对象(同名)?我看你在两个方法内都这样定义了:
      Idx: Integer;                
      NodeData: array [0..1000] of PTNodeData;
      Node_Bill: TTreeNode;
    如果说NodeData只能在一个作用域内,那其它两个变量(idx,node_bill),可是定义在public处的吧?
      

  31.   

    其它两个变量(idx,node_bill), 同NodeData一样的地方定义。
      

  32.   

    最后再问你一个,呵呵,其实我不太懂这些啊,
       TNodeData = packed record        //定义一个记录类型
           xiaohu_flag: Boolean;        //记录中的变量
      end;
      PTNodeData=^TNodedata;           //这个是表示什么意思,指针吗?
      NodeData: array [0..1000] of PTNodeData; //nodedata与ptnodedata是什么关系,
      New(NodeData[idx]);   //这个又是什么呢,
      Node_bill.Data := NodeData[Idx];  //node_bill.data表示的是什么啊?
      NodeData[Idx].xiaohu_flag  //指针,数组都快晕了~
    谢谢你啊,只能说谢谢你了,~~~~~!!!!
      

  33.   

    TNodeData是记录, PTNodeData=^TNodedata是记录指针, NodeData: array [0..1000] of PTNodeData;指针数组Node.Data是无类型指针 , New(NodeData[idx]) 初始化指针(创建一个新的动态变量并且把指针指向它)
    Node_bill.Data := NodeData[Idx]; 指针复制NodeData[Idx].xiaohu_flag 读取记录指针指向的内存空间中某个字段数据
      

  34.   

    嗯,运行过程知道了,可是还不是很懂整个的原理,为什么要采用这种指针数组~~~~-_-~~~
    PTNodeData(Node.Data). 这样是表示什么呢?
      

  35.   

    呵呵。挺刻苦的啊。
    PTNodeData(Node.Data)把无类型指针转换成PTNodeData类型指针。
    数组是为了保存多个节点数据指针
      

  36.   

    嗯,呵呵,跟了半天了,刚刚我看了下指针数组跟数组指针的区别.
    那可不可以不用无类型指针node.data,这个应该是相当于一个中间变量一样的吧,这个是在任何一个方法里面都可以用的吗,无须定义? 直接用这样 nodedata[idx].xiaohu_flag 来判断可不可以? (好像不行,这个指针数组是只能在一个作用域内的)老大,你QQ多少啊?以后还会向你请教的呢~