简体   繁体   English

不能 select 虚拟树视图中的根节点

[英]Cannot select the root node in Virtual Tree View

I am using Delphi XE3 with Virtual Tree View.我正在使用带有虚拟树视图的 Delphi XE3。

My codes are below:我的代码如下:

type
  TMyData = record
    Caption: string;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  RootNode: PVirtualNode;
  PData: ^TMyData;
begin
  RootNode := tvItems.AddChild(nil);
  PData := tvItems.GetNodeData(RootNode);
  PData^.Caption := 'This is a test node';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  tvItems.NodeDataSize := SizeOf(TMyData);
end;

procedure TForm1.tvItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  PData: ^TMyData;
begin
  if Assigned(Node) then
  begin
    PData := tvItems.GetNodeData(Node);

    if Assigned(PData) then
      Celltext := PData^.Caption;
  end;
end;

When I click the "Button1", the root node will be created.当我单击“Button1”时,将创建根节点。 However, when my mouse clicks the node text, it will not be selected.但是,当我的鼠标单击节点文本时,它不会被选中。

Some of my findings:我的一些发现:

  1. One must clicks to the beginning of the node text to select the node.必须点击节点文本到 select 节点的开头。 If clicking in middle or in the end of the node text, then the node will not be selected.如果单击节点文本的中间或末尾,则不会选择节点。

  2. If I change tvItemsGetText to below, then the problem disappears:如果我将 tvItemsGetText 更改为以下,那么问题就会消失:

    procedure TForm1.tvItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
    var
      PData: ^TMyData;
    begin
      CellText := 'This is a test node';
    end;

I set a breakpoint in tvItemsGetText and find it will be invoked several times.我在 tvItemsGetText 中设置了一个断点,发现它会被多次调用。 At the first several times, the PData will be nil, which makes the CellText empty.在前几次,PData 将为 nil,这使 CellText 为空。 At the final invokation, the PData will become valid and the CellText will be set to 'This is a test node'.在最后一次调用时,PData 将变为有效并且 CellText 将设置为“这是一个测试节点”。

It seems that the range that allow mouse click and select the node is determined by the initial texts of the node.似乎允许鼠标单击和 select 节点的范围是由节点的初始文本确定的。 If the initial text is empty string, then one must click at the very beginning of the node to select it.如果初始文本为空字符串,则必须单击最开始的节点到 select 即可。

Is this a bug of Virtual Tree View?这是虚拟树视图的错误吗?

There are several ways to init new node by user data.有几种方法可以通过用户数据来初始化新节点。

1. Using OnInitNode event: 1. 使用OnInitNode事件:

procedure TForm5.Button1Click(Sender: TObject);
begin
  vt1.InsertNode(nil, amAddChildLast); // internal calls vt1InitNode
end;

procedure TForm5.vt1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
  var InitialStates: TVirtualNodeInitStates);
var
  PData: ^TMyData;
begin
  PData := Sender.GetNodeData(Node);
  PData^.Caption := 'This is a test node';
end;

2 Using UserData param 2 使用UserData参数

Variant 1. Dynamic data变体 1. 动态数据

Do not forget to remove InitNode event and dont set NodeDataSize property不要忘记删除InitNode事件并且不要设置NodeDataSize属性

type
  TMyData = record
    Caption: string;
  end;
  PMyData = ^TMyData;

procedure TForm5.Button1Click(Sender: TObject);
var
  p: PMyData;
begin
  New(p);
  p.Caption:='This is a test node'; 
  vt1.InsertNode(nil, amAddChildLast, p); // create node with initialized user data
  // by default VirtualTree use NodeDataSize = SizeOf(pointer), 
  // so there is no reason to use GetNodeDataSize event 
end;


procedure TForm5.vt1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; 
  Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
var
  PData: PMyData;
begin
  if Assigned(Node) then
  begin
    PData := PMyData(Sender.GetNodeData(Node)^); // little modification
    // for correct access to dynamic node data

    if Assigned(PData) then
      CellText := PData.Caption;
  end;
end;

procedure TForm5.vt1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  p: PMyData;
begin
  p:=PMyData(Sender.GetNodeData(Node)^);
  Dispose(p); // as you allocate memory for user data - you should free it to avoid memory leaks
end;

Variant 2. Objects变体 2. 对象

Add new private function to your form:将新的私有 function 添加到您的表单中:

  private
    { Private declarations }
    function GetObjectByNode<T: class>(Node: PVirtualNode): T; 
    // do not forget to include System.Generics.Collections to `uses`

realization:实现:

function TForm5.GetObjectByNode<T>(Node: PVirtualNode): T;
var
  NodeData: Pointer;
  tmpObject: TObject;
begin
  Result := nil;
  if not Assigned(Node) then
    exit;
  NodeData := vt1.GetNodeData(Node);
  if Assigned(NodeData) then
    tmpObject := TObject(NodeData^);

  if tmpObject is T then
    Result := T(tmpObject)
  else
    Result := nil;
end;

And the main code (almost identical to variant 1):主要代码(几乎与变体 1 相同):

procedure TForm5.Button1Click(Sender: TObject);
var
  d: TMyData;
begin
  d := TMyData.Create;
  d.Caption := 'This is a test node';
  vt1.InsertNode(nil, amAddChildLast, d);
end;

procedure TForm5.vt1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  d: TMyData;
begin
  d := GetObjectByNode<TMyData>(Node);
  d.Free;
end;

procedure TForm5.vt1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; 
  Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
var
  d: TMyData;
begin
  d := GetObjectByNode<TMyData>(Node);
  if Assigned(d) then
    CellText := d.Caption;
end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM