Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong><em>1. Is there a way to use VirtualTreeView for a master / detail grid view ?</em></strong></p> <p>No, there is no such feature available at this time and IMHO won't be, since that would involve a very big intervention to an existing code.</p> <p><strong><em>2. How to create fully functional header for a child node detail grid view ?</em></strong></p> <p>Considering few ways, how to simulate header look and behavior for child nodes I've found useful to use nested tree views for a detail grid view. This brings you the separateness for your detail data and allows you to minimize the whole simulation to positioning of the nested tree view into a child node's rectangle.</p> <p><strong><em>2.1. Startup project</em></strong></p> <p>In the following project I'm trying to show how complicated could be implement such an easy task like the positioning of a control inside of a child node could be (without involving the original VirtualTree code). Take it just as a startup project, not as a final solution.</p> <p><strong><em>2.2. Known issues &amp; limitations:</em></strong></p> <ul> <li>this project was written and tested to use only one child per root node, so don't be surprised with a behavior when you exceed this limit, because this was not designed nor even tested for</li> <li>when a double click column resize of a main tree animates the column resize, the nested tree views are overdrawn with lines when the canvas is being scrolled by the ScrollDC function</li> <li>to keep the VirtualTree code without changing I've overrided the method for scroll bars updating. It is used to update nested tree views bounds whenever the scrollbars needs to be updated</li> <li>current <code>OnExpanded</code> implementation fires the event before the range and scroll positions are fixed, what makes the code more complicated and with a big weakness - the bounds of a detail tree view are updated after the tree is shown, what can be sometimes visible</li> </ul> <p><strong><em>2.3. Project code</em></strong></p> <p>It was written and tested in Delphi 2009 with respect to use in Delphi 7. For commented version of a next code <a href="https://stackoverflow.com/revisions/12188882/1"><code>follow this link</code></a>:</p> <p><strong><em>Unit1.pas</em></strong></p> <pre><code>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) &gt; Sender.AbsoluteIndex(NewNode) then Sender.FocusedNode := Sender.GetPreviousSibling(OldNode) else if OldNode &lt;&gt; 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. </code></pre> <p><strong><em>Unit1.dfm</em></strong></p> <pre><code>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 = &lt; 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&gt; 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 </code></pre> <p><strong><em>2.4. Screenshot</em></strong></p> <p><img src="https://i.stack.imgur.com/1sj1K.png" alt="enter image description here"></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload