Delphi 是否可以将VirtualStringTree用于主详图栅格视图?

Delphi 是否可以将VirtualStringTree用于主详图栅格视图?,delphi,delphi-7,virtualtreeview,tvirtualstringtree,Delphi,Delphi 7,Virtualtreeview,Tvirtualstringtree,好吧,我这里有件很棘手的事。。。 我想绘制/使用ChildNode的标题。 我认为这个想法是合理的,因为在子节点中有头这样子节点就可以在表中指定。 是否有VST拥有的功能,或者根本不可能 谢谢你的帮助。1。有没有办法将VirtualTreeView用于主/明细网格视图? 不,目前没有这样的功能可用,IMHO也不会,因为这将涉及对现有代码的很大干预 2。如何为子节点详细信息网格视图创建功能齐全的标题? 考虑到一些方法,如何模拟子节点的标题外观和行为,我发现将嵌套树视图用于详图网格视图非常有用。这为

好吧,我这里有件很棘手的事。。。 我想绘制/使用ChildNode的标题。 我认为这个想法是合理的,因为在子节点中有头这样子节点就可以在表中指定。 是否有VST拥有的功能,或者根本不可能

谢谢你的帮助。

1。有没有办法将VirtualTreeView用于主/明细网格视图?

不,目前没有这样的功能可用,IMHO也不会,因为这将涉及对现有代码的很大干预

2。如何为子节点详细信息网格视图创建功能齐全的标题?

考虑到一些方法,如何模拟子节点的标题外观和行为,我发现将嵌套树视图用于详图网格视图非常有用。这为您带来了细节数据的独立性,并允许您将嵌套树视图定位到子节点矩形中的整个模拟最小化

2.1。启动项目

在下面的项目中,我试图展示实现如此简单的任务有多复杂,比如在子节点中定位控件(不涉及原始VirtualTree代码)。将其视为一个启动项目,而不是最终解决方案

2.2。已知问题和限制:

  • 这个项目是为了每个根节点只使用一个子节点而编写和测试的,所以当您超过这个限制时,不要对行为感到惊讶,因为这不是为您设计的,甚至不是为您测试的
  • 当双击主树的列调整大小设置列调整大小的动画时,当ScrollDC函数滚动画布时,嵌套的树视图会被线条覆盖
  • 为了保持VirtualTree代码不变,我已经覆盖了滚动条更新的方法。每当需要更新滚动条时,它用于更新嵌套的树视图边界
  • 当前的
    OnExpanded
    实现在范围和滚动位置固定之前触发事件,这使得代码更加复杂,并且有一个很大的缺点-在显示树后更新细节树视图的边界,这有时是可见的
2.3。项目代码

它是在Delphi 2009中编写并测试的,与Delphi 7中的使用有关。对于下一个代码的注释版本:

Unit1.pas

单元1;
接口
使用
窗口、消息、系统工具、变体、类、图形、控件、窗体、,
对话框、stdctrl、虚拟树;
类型
TVTSCROLLBARSUPDATEVENT=对象的过程(发送方:TBaseVirtualTree;DoRepaint:布尔);
TVirtualStringTree=类(VirtualTrees.TVirtualStringTree)
私有的
FOnUpdateScrollBars:TVTScrollBarsUpdateEvent;
公众的
过程更新滚动条(dorepoint:Boolean);推翻
出版
更新滚动条上的属性:TVTScrollBarsUpdateEvent读取FOnUpdateScrollBars写入FOnUpdateScrollBars;
结束;
类型
PNodeSubTree=^TNodeSubTree;
TNodeSubTree=class
FChildTree:TVirtualStringTree;
结束;
类型
TForm1=类(TForm)
按钮1:t按钮;
VirtualStringTree1:TVirtualStringTree;
过程表单创建(发送方:ToObject);
程序按钮1点击(发送方:ToObject);
程序VirtualStringTree1afterAutoFit列(发送方:TVTHeader);
过程VirtualStringTree1BeforeDrawTreeLine(发送方:TBaseVirtualTree;
节点:PVirtualNode;级别:整数;变量PosX:整数);
过程VirtualStringTree1崩溃(发送方:TBaseVirtualTree;
节点:PVirtualNode);
过程VirtualStringTree1ColumnResize(发送方:TVTHeader;
列:TColumnIndex);
过程VirtualStringTree1Expanded(发送方:TBaseVirtualTree;
节点:PVirtualNode);
过程VirtualStringTree1FocusChange(发送方:TBaseVirtualTree;OldNode,
NewNode:PVirtualNode;OldColumn,NewColumn:TColumnIndex;
允许变量:布尔值);
过程VirtualStringTree1FreeNode(发送方:TBaseVirtualTree;
节点:PVirtualNode);
过程VirtualStringTree1MeasureItem(发送方:TBaseVirtualTree;
TargetCanvas:TCanvas;节点:PVirtualNode;变量NodeHeight:Integer);
私有的
过程使子树无效(树:TBaseVirtualTree);
过程重定大小子树(树:TBaseVirtualTree);
过程更新subtreebounds(树:TBaseVirtualTree;节点:PVirtualNode);
更新滚动条上的过程(发送方:TBaseVirtualTree;dorepoint:Boolean);
公众的
{公开声明}
结束;
变量
表1:TForm1;
实施
{$R*.dfm}
{TVirtualStringTree}
过程TVirtualStringTree.UpdateScrollBars(DoRepaint:Boolean);
开始
继承;
如果HandleAllocated和Assigned(FOnUpdateScrollBars),则
FOnUpdateScrollBars(Self、DoRepaint);
结束;
{TForm1}
过程TForm1.FormCreate(发送方:TObject);
开始
ReportMemoryLeaksOnShutdown:=True;
VirtualStringTree1.NodeDataSize:=SizeOf(TNodeSubTree);
VirtualStringTree1.onUpdate滚动条:=onUpdate滚动条;
结束;
程序TForm1.按钮1单击(发送方:TObject);
变量
资料:PNodeSubTree;
节点:PVirtualNode;
开始
节点:=VirtualStringTree1.AddChild(nil);
节点:=VirtualStringTree1.AddChild(节点);
VirtualStringTree1.InitNode(节点);
数据:=VirtualStringTree1.GetNodeData(节点);
数据^:=TNodeSubTree.Create;
Data^.FChildTree:=TVirtualStringTree.Create(无);
使用Data.FChildTree do
开始
可见:=假;
父节点:=VirtualStringTree1;
高度:=150;
DefaultNodeHight:=21;
Header.AutoSizeIndex:=0;
Header.Font.Charset:=默认字符集;
Header.Font.Color:=clWindowText;
Header.Font.Height:=-11;
Header.Font.Name:=“Tahoma”;
Header.Font.Style:=[];
收割台高度:=21;
Header.Options:=[hoColumnResize,hoDrag,hoShowSortGlyphs,hoVisible];
TabStop:=假;
使用Header.Columns.Add do
开始
宽度:=
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, VirtualTrees;

type
  TVTScrollBarsUpdateEvent = procedure(Sender: TBaseVirtualTree; DoRepaint: Boolean) of object;
  TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
  private
    FOnUpdateScrollBars: TVTScrollBarsUpdateEvent;
  public
    procedure UpdateScrollBars(DoRepaint: Boolean); override;
  published
    property OnUpdateScrollBars: TVTScrollBarsUpdateEvent read FOnUpdateScrollBars write FOnUpdateScrollBars;
  end;

type
  PNodeSubTree = ^TNodeSubTree;
  TNodeSubTree = class
    FChildTree: TVirtualStringTree;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    VirtualStringTree1: TVirtualStringTree;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure VirtualStringTree1AfterAutoFitColumns(Sender: TVTHeader);
    procedure VirtualStringTree1BeforeDrawTreeLine(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Level: Integer; var PosX: Integer);
    procedure VirtualStringTree1Collapsed(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure VirtualStringTree1ColumnResize(Sender: TVTHeader;
      Column: TColumnIndex);
    procedure VirtualStringTree1Expanded(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure VirtualStringTree1FocusChanging(Sender: TBaseVirtualTree; OldNode,
      NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
      var Allowed: Boolean);
    procedure VirtualStringTree1FreeNode(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure VirtualStringTree1MeasureItem(Sender: TBaseVirtualTree;
      TargetCanvas: TCanvas; Node: PVirtualNode; var NodeHeight: Integer);
  private
    procedure InvalidateSubTrees(Tree: TBaseVirtualTree);
    procedure ResizeSubTrees(Tree: TBaseVirtualTree);
    procedure UpdateSubTreeBounds(Tree: TBaseVirtualTree; Node: PVirtualNode);
    procedure OnUpdateScrollBars(Sender: TBaseVirtualTree; DoRepaint: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TVirtualStringTree }

procedure TVirtualStringTree.UpdateScrollBars(DoRepaint: Boolean);
begin
  inherited;
  if HandleAllocated and Assigned(FOnUpdateScrollBars) then
    FOnUpdateScrollBars(Self, DoRepaint);
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown := True;
  VirtualStringTree1.NodeDataSize := SizeOf(TNodeSubTree);
  VirtualStringTree1.OnUpdateScrollBars := OnUpdateScrollBars;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Data: PNodeSubTree;
  Node: PVirtualNode;
begin
  Node := VirtualStringTree1.AddChild(nil);
  Node := VirtualStringTree1.AddChild(Node);
  VirtualStringTree1.InitNode(Node);
  Data := VirtualStringTree1.GetNodeData(Node);
  Data^ := TNodeSubTree.Create;
  Data^.FChildTree := TVirtualStringTree.Create(nil);
  with Data.FChildTree do
  begin
    Visible := False;
    Parent := VirtualStringTree1;
    Height := 150;
    DefaultNodeHeight := 21;
    Header.AutoSizeIndex := 0;
    Header.Font.Charset := DEFAULT_CHARSET;
    Header.Font.Color := clWindowText;
    Header.Font.Height := -11;
    Header.Font.Name := 'Tahoma';
    Header.Font.Style := [];
    Header.Height := 21;
    Header.Options := [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible];
    TabStop := False;
    with Header.Columns.Add do
    begin
      Width := 100;
      Text := 'Header item 1';
    end;
    with Header.Columns.Add do
    begin
      Width := 100;
      Text := 'Header item 2';
    end;
  end;
end;

procedure TForm1.VirtualStringTree1AfterAutoFitColumns(Sender: TVTHeader);
begin
  InvalidateSubTrees(Sender.Treeview);
end;

procedure TForm1.VirtualStringTree1BeforeDrawTreeLine(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Level: Integer; var PosX: Integer);
begin
  if Level = 1 then
    PosX := 0;
end;

procedure TForm1.VirtualStringTree1Collapsed(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: PNodeSubTree;
begin
  Data := VirtualStringTree1.GetNodeData(Node.FirstChild);
  if Assigned(Data^) and Assigned(Data^.FChildTree) then
    Data^.FChildTree.Visible := False;
end;

procedure TForm1.VirtualStringTree1ColumnResize(Sender: TVTHeader;
  Column: TColumnIndex);
begin
  ResizeSubTrees(Sender.Treeview);
end;

procedure TForm1.VirtualStringTree1Expanded(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: PNodeSubTree;
begin
  Data := VirtualStringTree1.GetNodeData(Node.FirstChild);
  if Assigned(Data^) and Assigned(Data^.FChildTree) then
    Data^.FChildTree.Visible := True;
end;

procedure TForm1.VirtualStringTree1FocusChanging(Sender: TBaseVirtualTree;
  OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
  var Allowed: Boolean);
begin
  if Sender.GetNodeLevel(NewNode) = 1 then
  begin
    Allowed := False;
    if Sender.AbsoluteIndex(OldNode) > Sender.AbsoluteIndex(NewNode) then
      Sender.FocusedNode := Sender.GetPreviousSibling(OldNode)
    else
    if OldNode <> Sender.GetLastChild(nil) then
      Sender.FocusedNode := Sender.GetNextSibling(OldNode)
    else
      Sender.FocusedNode := OldNode;
  end;
end;

procedure TForm1.VirtualStringTree1FreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: PNodeSubTree;
begin
  Data := VirtualStringTree1.GetNodeData(Node);
  if Assigned(Data^) then
  begin
    if Assigned(Data^.FChildTree) then
      Data^.FChildTree.Free;
    Data^.Free;
  end;
end;

procedure TForm1.VirtualStringTree1MeasureItem(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; var NodeHeight: Integer);
var
  Data: PNodeSubTree;
begin
  if VirtualStringTree1.GetNodeLevel(Node) = 1 then
  begin
    Data := VirtualStringTree1.GetNodeData(Node);
    if Assigned(Data^) and Assigned(Data^.FChildTree) then
      NodeHeight := Data^.FChildTree.Height + 8;
  end;
end;

procedure TForm1.InvalidateSubTrees(Tree: TBaseVirtualTree);
var
  Data: PNodeSubTree;
  Node: PVirtualNode;
begin
  Node := Tree.GetFirst;
  while Assigned(Node) do
  begin
    if Tree.HasChildren[Node] then
    begin
      Data := Tree.GetNodeData(Node.FirstChild);
      if Assigned(Data^) and Assigned(Data^.FChildTree) then
      begin
        Data^.FChildTree.Header.Invalidate(nil);
        Data^.FChildTree.Invalidate;
      end;
    end;
    Node := Tree.GetNextSibling(Node);
  end;
end;

procedure TForm1.ResizeSubTrees(Tree: TBaseVirtualTree);
var
  Node: PVirtualNode;
begin
  Node := Tree.GetFirst;
  while Assigned(Node) do
  begin
    if Tree.HasChildren[Node] then
      UpdateSubTreeBounds(Tree, Node.FirstChild);
    Node := Tree.GetNextSibling(Node);
  end;
end;

procedure TForm1.UpdateSubTreeBounds(Tree: TBaseVirtualTree; Node: PVirtualNode);
var
  R: TRect;
  Data: PNodeSubTree;
begin
  if Assigned(Node) then
  begin
    Data := Tree.GetNodeData(Node);
    if Assigned(Data^) and Assigned(Data^.FChildTree) and
      Data^.FChildTree.Visible then
    begin
      R := Tree.GetDisplayRect(Node, -1, False, True);
      R.Left := R.Left + (Tree as TVirtualStringTree).Indent;
      R.Top := R.Top + 4;
      R.Right := R.Right - 8;
      R.Bottom := R.Bottom - 4;
      Data^.FChildTree.BoundsRect := R;
    end;
  end;
end;

procedure TForm1.OnUpdateScrollBars(Sender: TBaseVirtualTree; DoRepaint: Boolean);
begin
  ResizeSubTrees(Sender);
end;

end.
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 282
  ClientWidth = 468
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  DesignSize = (
    468
    282)
  PixelsPerInch = 96
  TextHeight = 13
  object VirtualStringTree1: TVirtualStringTree
    Left = 8
    Top = 8
    Width = 371
    Height = 266
    Anchors = [akLeft, akTop, akRight, akBottom]
    Header.AutoSizeIndex = 0
    Header.Font.Charset = DEFAULT_CHARSET
    Header.Font.Color = clWindowText
    Header.Font.Height = -11
    Header.Font.Name = 'Tahoma'
    Header.Font.Style = []
    Header.Height = 21
    Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoShowSortGlyphs, hoVisible]
    TabOrder = 0
    TreeOptions.MiscOptions = [toVariableNodeHeight]
    OnAfterAutoFitColumns = VirtualStringTree1AfterAutoFitColumns
    OnBeforeDrawTreeLine = VirtualStringTree1BeforeDrawTreeLine
    OnCollapsed = VirtualStringTree1Collapsed
    OnColumnResize = VirtualStringTree1ColumnResize
    OnExpanded = VirtualStringTree1Expanded
    OnFocusChanging = VirtualStringTree1FocusChanging
    OnFreeNode = VirtualStringTree1FreeNode
    OnMeasureItem = VirtualStringTree1MeasureItem
    ExplicitWidth = 581
    ExplicitHeight = 326
    Columns = <
      item
        Position = 0
        Width = 75
        WideText = 'Column 1'
      end
      item
        Position = 1
        Width = 75
        WideText = 'Column 2'
      end
      item
        Position = 2
        Width = 75
        WideText = 'Column 3'
      end>
  end
  object Button1: TButton
    Left = 385
    Top = 8
    Width = 75
    Height = 25
    Anchors = [akTop, akRight]
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
    ExplicitLeft = 595
  end
end