好吧,我在这里得到了一些非常棘手的东西……
我想将标题绘制/使用到ChildNode.
我认为这个想法是合理的,因为在子节点中有标题会让人看起来很棒,所以可以在表格中指定子节点.
是否有VST具有或根本不可能的功能?
我想将标题绘制/使用到ChildNode.
我认为这个想法是合理的,因为在子节点中有标题会让人看起来很棒,所以可以在表格中指定子节点.
是否有VST具有或根本不可能的功能?
谢谢你的帮助.
解决方法@H_403_9@
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,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,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.截图
不,目前没有这样的功能可用,恕我直言不会,因为这将涉及对现有代码的非常大的干预.
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,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,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.截图