是否有可能使用VirtualStringTree作为主细节网格视图?

好的,我在这里遇到了一些非常棘手的问题......我想将小标题绘制/使用到小孩节点。 我认为这个想法是合理的,因为在子节点中包含标题看起来会很神奇,所以可以在表中指定子节点。 VST有或根本无法做到这一点?

谢谢你的帮助。


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

不,目前没有这样的功能,恕我直言不会,因为这将涉及到对现有代码的非常大的干预。

2.如何为子节点细节网格视图创建功能齐全的标头?

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

2.1。 启动项目

在下面的项目中,我试图展示如何实现这样一个简单的任务,比如在子节点内的控件的定位可以是多么复杂(不涉及原始的VirtualTree代码)。 把它作为一个启动项目,而不是最终的解决方案。

2.2。 已知问题和限制:

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

    它是在Delphi 2009中针对Delphi 7中的应用编写和测试的。关于下一个代码的评论版本,请follow this link

    Unit1.pas

    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.
    

    Unit1.dfm

    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
    

    2.4。 截图

    在这里输入图像描述

    链接地址: http://www.djcxy.com/p/35027.html

    上一篇: Is it possible to use VirtualStringTree for a master detail grid view?

    下一篇: Embedding Controls In Cells