admin 管理员组文章数量: 887021
2023年12月17日发(作者:itoa函数touwenj)
VirtualTreeview使用说明
很好用的一个列表控件,可以用来代替Delphi自带的ListView和TreeView,而且也一直在更新,目前已经支持最新的XE2
官方网站:
SVN地址:/svn/trunk
基本的使用方法就不多说了,可以看看Demo,或者百度一下还是有些教程的。我这里只记录一些属性方法等,方便查阅
【属性】
EditDelay = 单元格编辑响应时间
HintAnimation = Hint动画效果
HintMode = Hint显示方式
LineMode = 网格线条模式
LineStyle = 网格线条样式
Header > AutoSizeIndex = 自适应宽度的列索引
Header > Options > hoAutoResize = 列自适应宽度开关
Header > Options > hoColumnResize = 是否可以自由调整列宽
Header > Options > hoDblClickResize = 双击分界线自动改变列度
Header > Options > hoDrag = 是否支持拖拽移动
Header > Options > hoHotTrack = 高亮显示当前列
Header > Options > hoHeightResize = 是否可以自由调整列高
TreeOptions > AutoOptions > toAutoExpand = 单击展开节点并收起其他节点
TreeOptions > AutoOptions > toAutoTristateTracking = 三态复选框自适应选择,即子节点被选择后父节点Check状态改变
TreeOptions > MiscOptions > toCheckSupport = 是否显示复选框。还需要设置节点的CheckType属性
TreeOptions > MiscOptions > toEditable = 是否允许单击编辑单元格
TreeOptions > MiscOptions > toFullRepaintOnResize = 控件大小改变时刷新显示数据
TreeOptions > MiscOptions > toToggleOnDblClick = 双击展开节点
TreeOptions > PaintOptions > toHideSelection = 隐藏选择焦点
TreeOptions > PaintOptions > toHotTrack = 当前行是否显示下划线
TreeOptions > PaintOptions > toShowDropmark = 拖拽时是否显示插入标记
TreeOptions > PaintOptions > toShowRoot = 是否显示父节点展开按钮
TreeOptions > PaintOptions > toShowHorzGridLines = 水平网格线开关
TreeOptions > PaintOptions > toShowTreeLines = 父节点与子节点的连接线
TreeOptions > PaintOptions > toShowVertGridLines = 垂直网格线开关
TreeOptions > PaintOptions > toThemeAware = 应用系统主题
TreeOptions > PaintOptions > toAlwaysHideSelection = 总是隐藏选择
TreeOptions > PaintOptions > toChildrenAbove = 父节点处于子节点下方
TreeOptions > SelectionOptions > toDisableDrawSelection = 框选开关
TreeOptions > SelectionOptions > toExtendedFocus = 是否允许Cloumn>0的单元格有焦点(有焦点的时候才能编辑)
TreeOptions > SelectionOptions > toFullRowSelect = 整行选择
TreeOptions > SelectionOptions > toMultiSelect = 是否可以多选
TreeOptions > SelectionOptions > toRightClickSelect = 右键是否可以选择
TreeOptions > SelectionOptions > toSimpleDrawSelection = 框选时只要该行处于框内即可被选择
TreeOptions > StringOptions > toShowStaticText = 是否显示静态文本(在节点正文后面显示的字符,静态文本不能编辑)
【方法】
TopNode = 设置列表顶部的节点,可以用来定位节点行
ScrollIntoView = 设置滚动条位置,可以用来定位节点行
【事件】
OnChange = 焦点改变时
OnCreateEditor = 设置某单元格的编辑框样式,比如TEdit,TComboBox等等。需要自己实现IVTEditLink接口,具体参看Advanced这个Demo
OnExpanded = 节点展开后触发
OnCollapsed = 节点收起后触发
OnPaintText = 设置单元内容字体效果,也可以画进度条等
OnHotChange = 热点节点改变时触发,也就是鼠标悬停时
单元格纵向位置及单元格高度
procedure 1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
begin
Node := 20; //纵向位置
ight[Node] := 20; //单元格高度
end;
动态调整列宽度
procedure 1Resize(Sender: TObject);
begin
s[1].Width := - s[1].Left - 25;
end;
单元格字体
procedure 3PaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node:
PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
var
Data: PPropertyData;
begin
// Make the root nodes underlined and draw changed nodes in bold style.
if = de then
:= [fsUnderline]
else
begin
Data := eData(Node);
if d then
:= [fsBold]
else
:= [];
end;
end;
单元格颜色
procedure 5BeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
begin
// Fill random cells with our own background, but don't touch the currently focused cell.
if Assigned(Node) and ((Column <> dColumn) or (Node <> dNode)) and
((Column - 2) = (Integer() mod ( - 1))) then
begin
:= $E0E0E0;
ct(CellRect);
end;
end;
隐藏行
eSubtree(nil, HideNodes, Pointer(ItemIndex), [], True);
procedure des(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort:
Boolean);
begin
ble[Node] := False;
end;
单元格编辑
1. 调用Editors单元
2. 消息处理函数
const
WM_STARTEDITING = WM_USER + 2000; //消息处理函数
procedure tEditing(var Message: TMessage);
var
Node: PVirtualNode;
Sender: TBaseVirtualTree;
begin
Sender := TBaseVirtualTree();
//Node := Pointer();
Node := dNode;
if Assigned(Node) then
de(Node, );
end;
//默认对当前选中行进行编辑
//指定待编辑的列
3. 触发编辑事件
TreeOptions := [toExtendedFocus,toFullRowSelect,toRightClickSelect];
procedure 1FocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
begin
with Sender do
begin
if Assigned(Node) and not (tsIncrementalSearching in TreeStates) then
begin
PostMessage(, WM_STARTEDITING, Integer(Sender), Column);
end;
end;
end;
4. 编辑事件控制
procedure 1Editing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
var Allowed: Boolean);
var
Data: PPropertyData;
begin
with Sender do
begin
Data := GetNodeData(Node);
Allowed := (ypes[Column] <> vtNone);
end;
end;
5. 创建编辑框
procedure 1CreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
out EditLink: IVTEditLink);
begin
EditLink := ;
end;
6. 内容改变
procedure 1PaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType);
var
Data: PPropertyData;
begin
Data := eData(Node);
if ds[Column] then
:= [fsBold]
else
:= [];
end;
(1) 这是一个可扩展到多层的树视图。视图就是单纯显示,无法与传入数据自动同步,必须手动写。
(2) 无论父节点还是子节点,传入数据必须是一个相同的结构(record),存放在其data属性里,通过“指针:=GetNodeData(节点)”获得地址,传入传出其“指针^.各结构属性”。
(3) 控件从RootNodeCount:=根节点数目大于0开始激发,立即激发onGetNodeDataSize,来获得传入结构数据的大小,此处可以返回sizeof(结构类型)。
(4) 然后对每个节点(包括已激发的子节点)进行OnInitNode,此处可以可以直接修改节点的属性,并用(2)的方法传入其data,以备以后调用。
(5) InitNode时,可以Include(InitialStates, ivsHasChildren)来说明含有字节点,但不会加载子节点。
如要加载,可以(1)界面直接双击打开,或者(2)代码Include(InitialStates, ivsExpanded)
亦可(3)直接调用ReinitChildren[父节点],(4)直接设置ount[父节点],来加载。
此时会激发onInitChildren,事件中可以设置ChildCount,然后对每一个子节点,一一激发InitNode。
(6) 每个节点激发(InitNode)后,会激发GetText,用于显示文本。此处可以根据Column来分别返回CellText。
(7) 如果某个节点Checktype设为ctCheckbox,则该节点前会增加check框,其值通过CheckState设定。
(8) 【bug】如果同为ctCheckbox,父子节点的CheckState是不关联的,也就是说,点选父节点,下属子节点一个也不会改变选值。
如需同步,就要在onCheck中用代码实现。我在本unit内,实现了
(a)父节点选中,则全部子节点也选中
(b)子节点全部选中,则父节点也选中
©子节点全部选空,则父节点也选空
即使onChecked事件即使加入了父子节点Checked同步代码,因为InitNode时不加载Child,未扩展开的子节点是无法调用onChecked代码与父节点同步的。
所以千万注意InitNode时,要用Children(Node,True);先履一遍字节点。
(9) VirtualStringTree各个事件内,许多Node参数不是“var”返回值的,所以对它们赋值于事无补。
如需要,最好使用“VirtualStringTree.各属性[节点]:=值”,具体值是否返回,可以查看VirtualStringTree源码。
(10)onGetImageIndex获得每个节点的图标,要搭配TImagelist控件;onGetHint获得每个节点的Hint。
一、【TVirtualStringTree常用属性】
BorderStyle :设置边框选项 bsSingle设置单边框
为TVirtualStringTree添加列及列标题:
Header--Columns : 设置列 点击“…”,在弹出界面点击add new按钮,就增加一列,在其text中输入列名,在width输入列宽度;
Header--options-hovisible: 设置列可显示!!
Header-Style :设置树的主题类型
ScrollBaroptions--AlwaysVisible 滚动条是否总是可见
ScrollBarOptions-ScrollBars-ssVertical 设置为只有竖向滚动条
为TVirtualStringTree添加勾选框、选择框、复选框:
TreeOptions----MiscOpitions---toCheckSupport 设置为True即可
CheckImageKind 为勾选框设置图标
Header-Maincolumn 设置勾选框在第几列前面,默认为0也就是在第一列前面
并设置ongettext()事件和onInitailNode()事件,见下面事件部分。
--------------------------------------------------------------------------------------------------------------------------------------------
二、 【TVirtualStringTree常用方法 】
taSize := sizeOf(TMyNodeData); //设置占存储空间大小
树节点选中:ed[p_node]True; //设置节点p_node处于选中状态
树节点勾选框选中:p_tate:=cscheckedNormal;//设置节点p_node处于勾选状态
onchecked()事件:设置节点勾选时触发的事件,其中第二个参数就是勾选的节点
取消选中的节点:election;
树节点删除: SelectedNodes; //删除选中的节点
树节点内容清空:;
得到树的第一个节点:st;
得到树的第一个选中节点:stSelected;
得到节点的下一个节点:t(p_node);
得到下一个选中的节点:tSelected(p_node);
得到父节点:p_
得到子节点个数:p_ount
得到第一个子节点:p_hild
得到最后一个子节点:p_hild
得到上一个兄弟节点:p_bling
得到下一个兄弟节点:p_bling
---------------------------------------------------------------------------------------------------------------------------
三、【TVirtualStringTree显示数据库字段内容】:
//定义一个指针
type
Tjdtransline =record
id: integer; //编号
name : string; //名称
levelID : integer;//级别,例如总公司levelID 为0、二级公司为1、三级公司levelID 为2等
FatherID:integer; //节点的父节点ID
end;
pjdtransline =^Tjdtransline ;
private
procedure iniVirtualStringTree1; //事件声明为全局私有事件
//树显示数据库字段内容
procedure tualStringTree1;
var
p_jdtransline: pjdtransline;
begin
while not do
begin
New(p_jdtransline);
p_jdtransline^.ID := client_dataset_yName('ID').AsInteger;
p_jdtransline^.Name := Trim(client_dataset_yName('Name').AsString);
ld(nil, p_jdtransline); //*********************添加树节点***********************************
;
end;
end;
//在窗体创建时调用树的初始化事件
procedure eate(sender:Tobject);
begin
iniVirtualStringTree1;
end;
//设置各列字段的显示OnGetText() var
p_node_data : PMyNodeData;
p_jdtransline : PJDTranslineTree;
begin
p_node_data := eData(Node);
p_jdtransline := p_node_data^.my_data_ptr;
case Column of
0 : CellText := inttostr( p_jdtransline^.ID);
1: CellText := p_jdtransline^.Name;
end;
end;
------------------------------------------------------------------------------------------------------------------------------------
四、 【TVirtualStringTree设置节点展开与折叠的图标 】
OnInitNode() //设置结点的节点是否有子节点类型(‘+’、‘—’显示)
begin
Include(InitialStates, ivsHasChildren);
ype := ctTriStateCheckBox;
end;
-------------------------------------------------VirtualStringTree树拖动操作实现开始-------------------------------------------------------------------------
五、【VirtualStringTree树节点拖动实现】
主要设置其DragOver和DragDrop事件。其中DragOver控制是否允许移动;DragDrop控制移动后执行的操作。
//一、DragOver事件
procedure lStringTree1Over(
Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState;
State: TDragState; Pt: TPoint; Mode: TDropMode; var Effect: Integer;
var Accept: Boolean);
//事件内部函数1.获取节点的值
function GetVNodeData(vn: PVirtualNode; vst: TVirtualStringTree): PVNodeData;
begin
Result := PVNodeData(PPointer(eData(vn))^);
end;
//事件内部函数2.获取所有选中节点的列表
function GetSelectedVNodes(vst: TVirtualStringTree): TVNodeArray;
var
list: TList;
n: PVirtualNode;
i: Integer;
begin
list := ;
n := stSelected;
while n <> nil do
begin
(n);
n := tSelected(n);
end;
SetLength(Result, );
for i := 0 to -1 do
begin
Result[i] := list[i];
end;
;
end;
// //事件内部函数3.判断是否是移动到自己的父节点
function IsSameLevel(selectedList: TVNodeArray): Boolean;
var
n: PVirtualNode;
l: Cardinal;
i: Integer;
begin
Result := False;
if Length(selectedList) = 0 then
begin
Result := True;
Exit;
end;
for i := 0 to High(selectedList) do
begin
n := selectedList[i];
if = rgetNode then //移动到自己父节点不允许移动
begin
[0].Text := '不允许移动到自己的父节点';
Result := True;
Break;
end;
end;
end;
// //事件内部函数4.判断目标(父、子)节点中是否与选中节点名称相同
function IsExistSelectObject(selectedList: TVNodeArray): Boolean;
var
dstNode : PVirtualNode;
n : PVirtualNode;
i : Integer;
TargetChildNode : PVirtualNode;
TargetParentNode : PVirtualNode;
SelectNodeName : String;
TargetNodeName : String;
TargetChildNodeName : String;
TargetParentNodeName: String;
SelectNodeLevel : Integer;
TargetNodeLevel : Integer;
begin
Result := False;
if Length(selectedList) = 0 then
begin
Exit;
end;
dstNode := rgetNode;
TargetChildNode := hild;
TargetParentNode := ;
TargetNodeName := pjdtransline(eData(dstNode)^).name;
TargetNodeLevel := pjdtransline(eData(dstNode)^).LevelID;
for i := 0 to High(selectedList) do
begin
n := selectedList[i];
SelectNodeName := pjdtransline(eData(n)^).name;
SelectNodeLevel := pjdtransline(eData(n)^).LevelID;
if (TargetNodeLevel > SelectNodeLevel) then //目标节点级别不能比选中节点级别低
begin
[0].Text := '目标节点级别比选中节点级别低,不能移动!';
Result := True;
Break;
end;
if (TargetNodeName = SelectNodeName) then //目标节点与选中节点相同
begin
[0].Text := '目标节点值与选中节点值相同,不能移动!';
Result := True;
Break;
end;
while TargetChildNode <> nil do
begin
TargetChildNodeName := pjdtransline(eData(TargetChildNode)^).name;
if TargetChildNodeName = SelectNodeName then //目标子节点与选中节点相同
begin
[0].Text := '目标子节点存在与选中节点值相同的节点,不能移动!';
Result := True;
Break;
end;
TargetChildNode := bling;
end;
end;
end;
// //事件内部函数6.判断是否移动自己子节点或子子节点
function IsAncestor(vnDescendant, vnAncestor: PVirtualNode): Boolean;
var
p: PVirtualNode;
begin
Result := False;
p := ;
while p <> nil do
begin
if p = vnAncestor then
begin
[0].Text := '不能移动到自己的子节点或子子节点';
Result := True;
Exit;
end;
p := ;
end;
end;
//事件定义变量
var
Node : TTreeNode;
VirtualStringTree1: TVirtualStringTree;
dstNode, srcNode: PVirtualNode;
srcText, dstText, s: string;
selectedList: TVNodeArray;
i: Integer;
begin
Accept := False;
if not (Source is TVirtualStringTree) then Exit;
VirtualStringTree1 := TVirtualStringTree(Source);
dstNode := rgetNode;
srcNode := dNode;
if (srcNode = nil) or (dstNode = nil) then Exit;
if srcNode = dstNode then
begin
[0].Text := '目标节点必须与选中节点不同!';
Exit;
end;
selectedList := GetSelectedVNodes(VirtualStringTree1);
if IsSameLevel(selectedList) then
begin
Accept := False;
Exit;
end;
if IsExistSelectObject(selectedList) then
begin
Accept := False;
Exit;
end;
// dstText := GetVNodeData(dstNode, VirtualStringTree1).Name;
case Mode of
dmAbove: // 成为父节点;
begin
Accept := False;
end;
dmBelow: // 成为子节点,本例主要采用成为子节点模式
begin
for i := 0 to High(selectedList) do
begin
srcNode := selectedList[i];
Accept := not IsAncestor(dstNode, srcNode);
if not Accept then Break;
end;
end;
dmOnNode: // 成为同级节点
begin
for i := 0 to High(selectedList) do
begin
srcNode := selectedList[i];
Accept := not IsAncestor(dstNode, srcNode);
if Accept then
[0].Text := '可以移动'
else
Break;
end;
end;
dmNowhere:
Accept := False;
else
end;
end;
二、DragDrop事件
procedure lStringTree1DragDrop(
Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject;
Formats: TFormatArray; Shift: TShiftState; Pt: TPoint;
var Effect: Integer; Mode: TDropMode);
//事件内部函数--获取选中节点的list
function GetSelectedVNodes(VtPurview: TVirtualStringTree): TVNodeArray;
var
list: TList;
n: PVirtualNode;
i: Integer;
begin
list := ;
n := stSelected;
while n <> nil do
begin
(n);
n := tSelected(n);
end;
SetLength(Result, );
for i := 0 to -1 do
begin
Result[i] := list[i];
end;
;
end;
var
VirtualStringTree1: TVirtualStringTree;
dstNode, srcNode: PVirtualNode;
selectedList: TVNodeArray;
i: Integer;
TargetNodeID : integer;
SelectNodeID : integer;
SelectNodeFID: integer;
sql_str : string;
begin
VirtualStringTree1 := TVirtualStringTree(Source);
dstNode := rgetNode;
TargetNodeID := PPurview(eData(dstNode)^).ID;
selectedList := GetSelectedVNodes(VirtualStringTree1);
srcNode := dNode;
if (srcNode = nil) or (dstNode = nil) then Exit;
case Mode of
dmAbove: // 成为父节点;
begin
end;
dmBelow: // 成为子节点
begin
if IDYES = MessageBox(Handle, PChar('是否将操作保存到数据库?'), '确认保存',MB_ICONQUESTION or
MB_YESNO or MB_DEFBUTTON2) then
begin
for i := 0 to High(selectedList) do
begin
srcNode := selectedList[i];
(srcNode, dstNode, amAddChildFirst, False);
SelectNodeID := PPurview(eData(srcNode)^).ID;
SelectNodeFID := PPurview(eData(srcNode)^).FatherID;
//执行数据库操作
if sql_str = '' then
sql_str := Format('exec p_VehicleGroupTreeDragMove %d,%d,%d ',
[SelectNodeID,
SelectNodeFID,
TargetNodeID
])
else
sql_str := sql_str + Format(';exec p_VehicleGroupTreeDragMove %d,%d,%d ',
[SelectNodeID,
SelectNodeFID,
TargetNodeID
]);
end;
(dstNode, 0, sdAscending, False);
end
else
exit;
end;
dmOnNode: // 成为同级节点
begin
end;
dmNowhere:
begin
end;
else
end;
if sql_str<>'' then
begin
ExcuteSQL(sql_str); //保存拖动后节点的上下级关系
end;
end;
-------------------------------------------------VirtualStringTree树拖动操作实现结束-------------------------------------------------------------------------
六、实现VirtualStringTree(TVirtualStringTree)树节点字体颜色分多颜色显示 oncellpaint()事件
客户要求盲区或掉线的字体要显示红色,速度值要显示灰色
代码如下:
procedure veVehiclePaintText(Sender: TBaseVirtualTree;
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType);
begin
p_node_data := tActiveVehicleNodeData(vtActiveVehicle, Node); //获取节点data
if not Assigned(p_node_data) then
Exit;
vInfo := PGPSClientVehicleInfoColumn(s[Column].Data);
if vInfo <> nil then
begin
if (Pos('盲区',p_node_data^.te)>0) and //判断节点值满足某条件
(vInfo^.ame = 'GPS_Speed') then //判断是哪个列,如果是整个节点都变颜色可不需此条件
:= clMedGray; //速度列变灰色
if (Pos('盲区',p_node_data^.te)>0) and
(vInfo^.ame = 'GPS_Precision') then
:= clred; //精度列变红色
if (SecondsBetween(Now(), p_node_data^.e)>=7200) and //盲区条件
(vInfo^.ame = 'GPS_Speed') then //速度列
:= clMedGray;
if (SecondsBetween(Now(), p_node_data^.e)>=7200) and
(vInfo^.ame = 'GPS_RealStatus') then
:= clred;
end;
版权声明:本文标题:[Delphi]VirtualTreeview使用说明 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1702745514h429084.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论