- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
好吧,我这里遇到了一些非常棘手的事情......我想将 header 绘制/使用到子节点。我认为这个想法是合理的,因为在子节点中包含标题看起来会很神奇,因此可以在表中指定子节点。VST 有什么功能或者根本不可能吗?
感谢您的帮助。
最佳答案
1。有没有办法将 VirtualTreeView 用于主/详细 GridView ?
不,目前没有这样的功能,恕我直言,也不会,因为这将涉及对现有代码的很大的干预。
2。如何为子节点详细信息 GridView 创建功能齐全的标题?
考虑到几种方法,如何模拟子节点的标题外观和行为,我发现使用嵌套 TreeView 作为详细 GridView 很有用。这为您带来了详细数据的分离性,并允许您最小化将嵌套 TreeView 定位到子节点矩形中的整个模拟。
2.1。启动项目
在下面的项目中,我试图展示实现如此简单的任务(例如在子节点内定位控件)可能有多复杂(不涉及原始 VirtualTree 代码)。仅将其视为启动项目,而不是最终解决方案。
2.2。已知问题和限制:
OnExpanded
实现在范围和滚动位置固定之前触发事件,这使得代码更加复杂并且有一个很大的弱点 - 详细 TreeView 的边界在树被更新后更新显示,有时可以看到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。截图
关于delphi - 是否可以使用 VirtualStringTree 作为主细节 GridView ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12146241/
是的,我知道我发布了很多问题,但那是因为我要么需要保证我做对了,我做错了什么,要么我完全一无所知,并且在文档中找不到任何东西。无论如何, 我正在尝试检查重复的节点。这是我想要的方式: 循环遍历我的节点
我有一个带有 X header 和 x 根的 virtualstringtree(启用了网格线)。 我想将子项(至少 1 个)添加到只有 1 个文本位于中间并通过所有标题(独立)的根中。因此,无论我是
我在窗体上有一个virtualstringtree控件,该控件必须显示图像列表中某些节点的图标。这很好用,但是,对于某些节点,还必须显示与节点和正方形一样高的自定义绘制图标。 我正在使用OnBefor
我想在单元格文本已完全显示时显示提示。 所以,在表单的 OnCreate 上 procedure TForm1.FormCreate(Sender: TObject); begin Virtual
是否可以隐藏 VirtualStringTree 中的特定节点?我正在实现“过滤”功能(VST 充当包含列的列表),并且我希望避免每次更改过滤器时重新加载内容 - 相反,更快的方法是告诉 VST 不要
我想每个曾经使用过Delphi的VirtualStringTree的人都会同意它是一个很棒的控件。它是一个“虚拟”控件(您的数据必须保存在其他地方),所以我在想什么数据结构最适合这样的任务? IMO认
如果 VirtualStringTree 中的节点是多行的(与 Node.States 中的 Multiline 相比),那么如何使该节点中所有列(多行列除外)的文本垂直居中? 我尝试使用OnBefo
我正在尝试更改节点的索引,因为有些特定节点始终需要位于树的底部。我试图更改 Node.Index,但这并没有改变任何东西。所以我的问题是:如何更改 PVirtualNode 的索引? 谢谢! - 杰夫
VirtualStringTree的滚动条如何刷新如果每个节点高度都更改为不同的高度。因为,滚动仍然处于相同状态,导致滚动时无法查看其他节点。 toVariableNodeHeight选项不起作用?还
我有一个带有 X 个根和 X 个子节点的 VirtualStringTree。 每个根都有一个特殊的 NodeData 分配。 每个子节点都分配了另一个 NodeData。 我怎么知道 OnFreeN
我启用了 MultiSelect 选项的 VST。 How can I retrieve the list of selected nodes in VirtualStringTree when th
我正在寻找一个程序或某些东西,如果我右键单击一个节点(或通常在 VirtualStringTree 上),它就会被触发 我有以下场景: 我的 VST 接近 ListView 。 我只能用鼠标多选根节点
是否可以锁定VirtualStringTree中的第0列(带有节点名称)像在 Excel 中一样水平滚动吗? 最佳答案 如果我没记错的话,此功能是在版本 5 中引入的。要在其 Options 中设置列
我目前在树的 OnBeforeCellPaint 事件中使用此代码: if Node.Index mod 2 = 0 then begin TargetCanvas.Brush.Color :=
我使用 virtualstringtree 一段时间了。我将它用于两个不同的用途,首先是一个用于选择、显示数据的普通树,其次是作为一个网格来显示 SQL 语句的输出。 我加载到树中的所有数据都来自数据
我有一个包含 3 列的 VST,均匀地占用可用空间。 我已在 Header.Options 中设置了 hoAutoSpring,并且 所有列都设置了 Column[x].Option 和 coAuto
所以,我的最终目标是找到一种方法,通过客户端区域内的添加/删除按钮来列出项目(例如 vsReport 中的 TListView)。 例如: |----------------| |Old Item 1
我正在尝试将项目从 D6 移动到 D-XE3。使用 VirtualStringTree 5.10 版本在 OnSaveNode 和 OnLoadEvents 中保存和加载树数据时,我遇到了垃圾。我可能
当从控件拖动到 VirtualStringTree 时,如果该控件具有 TDragObject,则预计将其用作 OnDragDrop 和 OnDragOver 中的源,但它始终返回该组件。我相信这是一
我正在严格按照本教程来保存和加载我的 VirtualStringTree:http://wiki.freepascal.org/VirtualTreeview_Example_for_Lazarus我
我是一名优秀的程序员,十分优秀!