加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 单元格中的VirtualTreeView嵌入按钮

发布时间:2020-12-15 09:23:05 所属栏目:大数据 来源:网络整理
导读:我正在尝试使用TButton创建节点. 我创建节点和链接到节点的按钮. 在事件TVirtualStringTree.AfterCellPaint上,我初始化按钮上的BoundsRect.但按钮始终显示在第一个节点中. 你对这个问题有所了解吗? type TNodeData = record TextValue: string; Button: TBu
我正在尝试使用TButton创建节点.
我创建节点和链接到节点的按钮.
在事件TVirtualStringTree.AfterCellPaint上,我初始化按钮上的BoundsRect.但按钮始终显示在第一个节点中.

你对这个问题有所了解吗?

type
  TNodeData = record
    TextValue: string;
    Button: TButton;
  end;
  PNodeData = ^TNodeData;

procedure TForm1.FormCreate(Sender: TObject);

  procedure AddButton(__Node: PVirtualNode);
  var
    NodeData: PNodeData;
  begin
    NodeData := VirtualStringTree1.GetNodeData(__Node);
    NodeData.Button := TButton.Create(nil);
    with NodeData.Button do
    begin
      Parent := VirtualStringTree1;
      Height := VirtualStringTree1.DefaultNodeHeight;
      Caption := '+';
      Visible := false;
    end;
  end;

  procedure InitializeNodeData(__Node: PVirtualNode; __Text: string);
  var
    NodeData: PNodeData;
  begin
    NodeData := VirtualStringTree1.GetNodeData(__Node);
    NodeData.TextValue := __Text;
  end;

var
  Node: PVirtualNode;
begin
  VirtualStringTree1.NodeDataSize := SizeOf(TNodeData);

  Node := VirtualStringTree1.AddChild(nil);
  InitializeNodeData(Node,'a');      
  Node := VirtualStringTree1.AddChild(Node);
  InitializeNodeData(Node,'a.1');

  Node := VirtualStringTree1.AddChild(nil);
  InitializeNodeData(Node,'b');
  Node := VirtualStringTree1.AddChild(Node);
  InitializeNodeData(Node,'Here the button');
  AddButton(Node);
end;

procedure TForm1.VirtualStringTree1AfterCellPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect);
var
 NodeData: PNodeData;
begin
  if (Column = 0) then
    Exit;

  NodeData := VirtualStringTree1.GetNodeData(Node);
  if (Assigned(NodeData)) and (Assigned(NodeData.Button)) then
  begin
    with NodeData.Button Do
    begin
      Visible := (vsVisible in Node.States)
                 and ((Node.Parent = VirtualStringTree1.RootNode) or   (vsExpanded in Node.Parent.States));
      BoundsRect := CellRect;
    end;
  end;
end;

解决方法

所以iamjoosy的答案问题是 – 即使它有效 – 只要你用绘制的按钮/ images /滚动滚动这个树,那些应该再次离开Tree的那些仍然存在,被绘制在最低层/你离开他们的最高位置.根据您刚刚滚动的数量,它会在该列中留下更小或更大的按钮杂乱. AfterCellPaint不再移动它们,因为现在隐藏在底部/顶部上方的隐藏节点的单元格不再被绘制.

您可以做的是遍历所有树节点(如果您有很多节点,可能非常昂贵)并检查它们是否实际位于树的可见区域并隐藏面板(您可能需要在面板内部绘制按钮)相应地使用你的按钮/ whatevers,而不是后面的树的顶部:

procedure TMyTree.MyTreeAfterCellPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  CellRect: TRect);
var
  InitialIndex: Integer;
// onInitNode I AddOrSetValue a "DataIndexList" TDictionary<PVirtualNode,LongInt>
// to preserve an original index "InitialIndex" (violating the virtual paradigm),// because I need it for something else anyways
  Data: PMyData;
  ANode: PVirtualNode;
begin
  if Node <> nil then
  begin
    if Column = 2 then
    begin
      ANode := MyTree.GetFirst;
      while Assigned(ANode) do
      begin
        DataIndexList.TryGetValue(ANode,InitialIndex);
        if not ( CheckVisibility(Sender.GetDisplayRect(ANode,Column,False)) ) then
        begin
          MyBtnArray[InitialIndex].Visible := False;
          MyPanelArray[InitialIndex].Visible := False;
        end
        else
        begin
          MyBtnArray[InitialIndex].Visible := True;
          MyPanelArray[InitialIndex].Visible := True;
        end;
        ANode := MyTree.GetNext(ANode);
      end;
      DataIndexList.TryGetValue(Node,InitialIndex);
      Data := MyTree.GetNodeData(Node);
      MyPanelArray[InitialIndex].BoundsRect := Sender.GetDisplayRect(Node,False);
    end;
  end;
end;

function TMyTree.CheckVisibility(R: TRect): Boolean;
begin
// in my case these checks are the way to go,because
// MyTree is touching the top border of the TForm.  You will have
// to adjust accordingly if your placement is different
  if (R.Bottom < MyTree.Top) or (R.Bottom > MyTree.Top + MyTree.Height) then
    Result := False
  else
    Result := True;
end;

不用说,您可以成功地在许多其他OnEvents中使用visibilityCheck进行遍历.它不必在AfterCellPaint中;也许另一个事件可能是更好的表现明智.

要创建一个原始Panel Button的RunTime副本,要放置在ButtonArray或您正在使用的任何结构中,您还必须复制它们的RTTI.此过程取自http://www.blong.com/Conferences/BorConUK98/DelphiRTTI/CB140.zip(http://www.blong.com/Conferences/BorConUK98/DelphiRTTI/CB140.htm的进一步RTTI信息)和“使用TypInfo”:

procedure CopyObject(ObjFrom,ObjTo: TObject);
var
  PropInfos: PPropList;
  PropInfo: PPropInfo;
  Count,Loop: Integer;
  OrdVal: Longint;
  StrVal: String;
  FloatVal: Extended;
  MethodVal: TMethod;
begin
  { Iterate thru all published fields and properties of source }
  { copying them to target }

  { Find out how many properties we'll be considering }
  Count := GetPropList(ObjFrom.ClassInfo,tkAny,nil);
  { Allocate memory to hold their RTTI data }
  GetMem(PropInfos,Count * SizeOf(PPropInfo));
  try
    { Get hold of the property list in our new buffer }
    GetPropList(ObjFrom.ClassInfo,PropInfos);
    { Loop through all the selected properties }
    for Loop := 0 to Count - 1 do
    begin
      PropInfo := GetPropInfo(ObjTo.ClassInfo,PropInfos^[Loop]^.Name);
      { Check the general type of the property }
      { and read/write it in an appropriate way }
      case PropInfos^[Loop]^.PropType^.Kind of
        tkInteger,tkChar,tkEnumeration,tkSet,tkClass{$ifdef Win32},tkWChar{$endif}:
        begin
          OrdVal := GetOrdProp(ObjFrom,PropInfos^[Loop]);
          if Assigned(PropInfo) then
            SetOrdProp(ObjTo,PropInfo,OrdVal);
        end;
        tkFloat:
        begin
          FloatVal := GetFloatProp(ObjFrom,PropInfos^[Loop]);
          if Assigned(PropInfo) then
            SetFloatProp(ObjTo,FloatVal);
        end;
        {$ifndef DelphiLessThan3}
        tkWString,{$endif}
        {$ifdef Win32}
        tkLString,{$endif}
        tkString:
        begin
          { Avoid copying 'Name' - components must have unique names }
          if UpperCase(PropInfos^[Loop]^.Name) = 'NAME' then
            Continue;
          StrVal := GetStrProp(ObjFrom,PropInfos^[Loop]);
          if Assigned(PropInfo) then
            SetStrProp(ObjTo,StrVal);
        end;
        tkMethod:
        begin
          MethodVal := GetMethodProp(ObjFrom,PropInfos^[Loop]);
          if Assigned(PropInfo) then
            SetMethodProp(ObjTo,MethodVal);
        end
      end
    end
  finally
    FreeMem(PropInfos,Count * SizeOf(PPropInfo));
  end;
end;

看到我以后的这个旧答案,我现在有一个不同的解决方案运行VisibilityCheck,这是更可靠和更容易:

function TFoo.IsNodeVisibleInClientRect(Node: PVirtualNode; Column: TColumnIndex = NoColumn): Boolean;
begin
  Result := VST.IsVisible[Node] and
    VST.GetDisplayRect(Node,False).IntersectsWith(VST.ClientRect);
end;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读