2012-08-27 98 views
8

好吧我在這裏得到了一些非常棘手的問題... 我想繪製/使用Header到一個ChildNode。 我認爲這個想法是合理的,因爲在子節點中使用標題看起來會很神奇,所以可以在表中指定子節點。 VST是否有這樣的功能?是否可以將VirtualStringTree用於主細節網格視圖?

感謝您的幫助。

+1

上次我調查了這樣的想法,我結束了使用VirtualTreeView它在所有的拋棄,並用類似的Developer Express公司,其內置了這種能力快速量子電網。這有點一個網格內的網格(嵌套網格)比這個點上的樹形視圖更多。 –

+1

@Warren,你關於網格內部網格的觀點*給我帶來了一個瘋狂的想法,在虛擬樹視圖內部創建一個嵌套的虛擬樹視圖,並控制它在崩潰時的可見性以及展開節點事件。這比模擬它更容易實現。 – TLama

+0

所以不是不可能的? –

回答

14

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。截圖

enter image description here

+1

這是我見過的最令人印象深刻的代碼!希望我可以給你更多的代表! –

+0

toVariableNodeHeight在TreeOptions.MiscOptions中缺失,這是此示例項目所需的,否則不會調用OnMeasureItem。 –

+0

@Joachim,謝謝你的提示!我相當確定我複製了項目,因爲它是在我截取屏幕截圖的時候,所以它可能只是VT的一些舊版本,即使沒有包含在「MiscOptions」集合中的這個選項,也會觸發'OnMeasureItem'事件。不幸的是,我沒有提及那次我使用哪個版本來驗證。 – TLama

相關問題