2012-08-27 28 views
8

Được rồi, tôi có một thứ rất khó ở đây ... Tôi muốn BẢN V// SỬ DỤNG Tiêu đề cho một ChildNode. Tôi nghĩ rằng ý tưởng này là hợp lý vì nó sẽ trông tuyệt vời để có tiêu đề trong các nút con để các nút con có thể được chỉ định trong một bảng. Có tính năng nào mà VST có hoặc hoàn toàn không thể?Có thể sử dụng VirtualStringTree cho chế độ xem lưới chi tiết chính không?

Cảm ơn sự giúp đỡ của bạn.

+1

Thời gian qua tôi điều tra một ý tưởng như vậy, tôi đã kết thúc từ bỏ sử dụng VirtualTreeView cho nó chút nào, và sử dụng một cái gì đó như Express Quantum Grid từ Developer Express, trong đó có khả năng như vậy được xây dựng trong. Đó là loại của nhiều lưới bên trong lưới (lưới lồng) hơn so với chế độ xem dạng cây tại điểm đó. –

+1

@ Warren, quan điểm của bạn về * lưới bên trong lưới * mang đến cho tôi một ý tưởng điên rồ, tạo ra một khung nhìn cây ảo bên trong một khung nhìn cây ảo và kiểm soát khả năng hiển thị của nó khi thu gọn và mở rộng các sự kiện nút. Điều này chắc chắn sẽ dễ thực hiện hơn là mô phỏng nó. – TLama

+0

Vì vậy, không phải không thể? –

Trả lời

14

1. Có cách nào để sử dụng VirtualTreeView cho chế độ xem lưới chính/chi tiết không?

Không, không có tính năng như vậy tại thời điểm này và IMHO sẽ không, vì điều đó sẽ liên quan đến sự can thiệp rất lớn đối với mã hiện có.

2. Cách tạo tiêu đề đầy đủ chức năng cho chế độ xem lưới chi tiết nút con?

Xem xét một vài cách, cách mô phỏng giao diện đầu trang và hành vi cho các nút con Tôi thấy hữu ích khi sử dụng chế độ xem lồng nhau cho chế độ xem lưới chi tiết. Điều này mang đến cho bạn sự tách biệt cho dữ liệu chi tiết của bạn và cho phép bạn giảm thiểu toàn bộ mô phỏng về vị trí của khung nhìn cây lồng nhau thành hình chữ nhật của nút con.

2.1. Dự án khởi động

Trong dự án sau đây, tôi đang cố gắng thể hiện sự phức tạp như thế nào khi điều khiển bên trong nút con có thể (không liên quan đến mã VirtualTree gốc). Mang nó như một dự án khởi động, không phải là một giải pháp cuối cùng.

2.2. Vấn đề đã biết & hạn chế:

  • dự án này đã được viết và kiểm tra để chỉ sử dụng một đứa trẻ mỗi nút gốc, vì vậy đừng ngạc nhiên với một hành vi khi bạn vượt quá giới hạn này, bởi vì đây không được thiết kế cũng không thậm chí thử nghiệm cho
  • khi cột nhấp đúp thay đổi kích thước của cây chính sẽ làm thay đổi kích thước cột, các chế độ xem lồng nhau được vẽ bằng các dòng khi canvas đang được cuộn bởi hàm ScrollDC
  • để giữ mã VirtualTree mà không thay đổi ' đã ghi đè phương thức cho các thanh cuộn đang được cập nhật. Nó được sử dụng để cập nhật các giới hạn xem cây lồng nhau bất cứ khi nào thanh cuộn cần được cập nhật
  • hiện tại OnExpanded triển khai sự kiện trước khi phạm vi và vị trí cuộn được cố định, điều khiến mã trở nên phức tạp hơn và có điểm yếu lớn - giới hạn của chi tiết xem cây được cập nhật sau khi cây được hiển thị, những gì có thể đôi khi có thể nhìn thấy

2,3. Mã dự án

Nó được viết và thử nghiệm trong Delphi 2009 liên quan đến sử dụng trong Delphi 7.Đối với phiên bản nhận xét của một mã tiếp theo 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. Ảnh chụp màn hình

enter image description here

+1

Đây là mã ấn tượng nhất mà tôi từng thấy trong đời! Ước gì tôi có thể cung cấp cho bạn nhiều điểm đại diện hơn cho việc này! –

+0

toVariableNodeHeight bị thiếu trong TreeOptions.MiscOptions, điều này là cần thiết cho dự án mẫu này, nếu không thì OnMeasureItem không được gọi. –

+0

@ Joachim, cảm ơn gợi ý! Tôi khá chắc chắn rằng tôi đã sao chép dự án vào lúc tôi chụp ảnh màn hình, vì vậy nó có thể chỉ là một phiên bản cũ của VT đã kích hoạt sự kiện 'OnMeasureItem' ngay cả khi không có tùy chọn này trong tập' MiscOptions'. Thật không may tôi đã không đề cập đến phiên bản tôi đã sử dụng thời gian đó để xác minh. – TLama

Các vấn đề liên quan