如何使用 DragType dtOLE 将节点从 TVirtualStringTree 拖放到 VCL 控件中?
How to drag and drop nodes from TVirtualStringTree into a VCL control with DragType dtOLE?
当 DragType
设置为 dtOLE
(不是 dtVCL
)时,是否可以将节点从 TVirtualStringTree
拖放到 VCL 控件中
我有一种情况需要能够将节点从一个 VT 拖动到另一个 VT(dtOLE
工作正常),但同时,在拖动时,我需要一个选项能够将节点放入 TListBox
(或其他 VCL 控件)。
我尝试为 TListBox
句柄设置 DragAcceptFiles()
API,但没有效果。
如何做到?
TListBox
上没有 DragAcceptFiles
属性。如果您的意思是您在 TListBox.Handle
window 上调用 Win32 API DragAcceptFiles()
函数,则只有在以下情况下才有效:
您手动子class TListBox.WindowProc
属性 来处理WM_DROPFILES
window 消息。
TVirtualStringTree
提供 OLE 拖动时的 CF_HDROP
格式。
但是,2 并非如此。 CF_HDROP
仅用于拖动文件系统路径,而不是 TVirtualStringTree
拖动的内容。所以使用 DragAcceptFiles()
已经过时了。
TVirtualStringTree
(以及其他 TBaseVirtualTree
后代)在 OLE 拖动期间使用自定义数据格式(VirtualTrees.pas
单元的界面部分声明了这些格式 ID,因此您不需要在您自己的代码中手动注册它们):
CF_VIRTUALTREE
包含一个 IStream
或 HGLOBAL
保存正在拖动的选定树节点的序列化形式。序列化由一系列描述每个节点的数据块组成。你将不得不参考 VirtualTree.pas
单元的实现来破译这种格式(我不打算在这里做)。
CF_VTREFERENCE
包含一个 HGLOBAL
持有一个 TVTReference
记录(也在 VirtualTrees.pas
单元的接口部分中声明)包含一个指向从中拖动的实际 TBaseVirtualTree
对象的指针以及树所属进程的 ID。
因此,为了能够将树节点放到 TListBox
上,您必须执行以下操作:
写一个 class 来实现 IDropTarget
interface (or use a pre-existing implementation, such as from Anders Melander's Drag&Drop suite).
向 TListBox.Handle
window 注册 class
在您的 IDropTarget
实现中,您可以查询提供的 IDataObject
以获取 CF_VIRTUALTREE
和 CF_VTREFERENCE
格式。如果成功,您的 Drop()
方法将可以访问正在拖动的树节点数据,并可以根据需要将其复制到 TListBox
中。
假设您的 TListBox
存在于与被拖出的 TVirtualStringTree
相同的进程中,我建议只关注 CF_VTREFERENCE
,因为它是一种非常小且简单的格式(请参阅 TBaseVirtualTree.GetTreeFromDataObject()
方法的实现),当您可以通过源 TVirtualStringTree
直接代替。
当 DragType
设置为 dtOLE
(不是 dtVCL
)时,是否可以将节点从 TVirtualStringTree
拖放到 VCL 控件中
我有一种情况需要能够将节点从一个 VT 拖动到另一个 VT(dtOLE
工作正常),但同时,在拖动时,我需要一个选项能够将节点放入 TListBox
(或其他 VCL 控件)。
我尝试为 TListBox
句柄设置 DragAcceptFiles()
API,但没有效果。
如何做到?
TListBox
上没有 DragAcceptFiles
属性。如果您的意思是您在 TListBox.Handle
window 上调用 Win32 API DragAcceptFiles()
函数,则只有在以下情况下才有效:
您手动子class
TListBox.WindowProc
属性 来处理WM_DROPFILES
window 消息。TVirtualStringTree
提供 OLE 拖动时的CF_HDROP
格式。
2 并非如此。 CF_HDROP
仅用于拖动文件系统路径,而不是 TVirtualStringTree
拖动的内容。所以使用 DragAcceptFiles()
已经过时了。
TVirtualStringTree
(以及其他 TBaseVirtualTree
后代)在 OLE 拖动期间使用自定义数据格式(VirtualTrees.pas
单元的界面部分声明了这些格式 ID,因此您不需要在您自己的代码中手动注册它们):
CF_VIRTUALTREE
包含一个IStream
或HGLOBAL
保存正在拖动的选定树节点的序列化形式。序列化由一系列描述每个节点的数据块组成。你将不得不参考VirtualTree.pas
单元的实现来破译这种格式(我不打算在这里做)。CF_VTREFERENCE
包含一个HGLOBAL
持有一个TVTReference
记录(也在VirtualTrees.pas
单元的接口部分中声明)包含一个指向从中拖动的实际TBaseVirtualTree
对象的指针以及树所属进程的 ID。
因此,为了能够将树节点放到 TListBox
上,您必须执行以下操作:
写一个 class 来实现
IDropTarget
interface (or use a pre-existing implementation, such as from Anders Melander's Drag&Drop suite).- 向
在您的
IDropTarget
实现中,您可以查询提供的IDataObject
以获取CF_VIRTUALTREE
和CF_VTREFERENCE
格式。如果成功,您的Drop()
方法将可以访问正在拖动的树节点数据,并可以根据需要将其复制到TListBox
中。
TListBox.Handle
window 注册 class
假设您的 TListBox
存在于与被拖出的 TVirtualStringTree
相同的进程中,我建议只关注 CF_VTREFERENCE
,因为它是一种非常小且简单的格式(请参阅 TBaseVirtualTree.GetTreeFromDataObject()
方法的实现),当您可以通过源 TVirtualStringTree
直接代替。