如何使用 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() 函数,则只有在以下情况下才有效:

  1. 您手动子class TListBox.WindowProc 属性 来处理WM_DROPFILES window 消息。

  2. TVirtualStringTree 提供 OLE 拖动时的 CF_HDROP 格式。

但是,

2 并非如此。 CF_HDROP 仅用于拖动文件系统路径,而不是 TVirtualStringTree 拖动的内容。所以使用 DragAcceptFiles() 已经过时了。

TVirtualStringTree(以及其他 TBaseVirtualTree 后代)在 OLE 拖动期间使用自定义数据格式(VirtualTrees.pas 单元的界面部分声明了这些格式 ID,因此您不需要在您自己的代码中手动注册它们):

  • CF_VIRTUALTREE 包含一个 IStreamHGLOBAL 保存正在拖动的选定树节点的序列化形式。序列化由一系列描述每个节点的数据块组成。你将不得不参考 VirtualTree.pas 单元的实现来破译这种格式(我不打算在这里做)。

  • CF_VTREFERENCE 包含一个 HGLOBAL 持有一个 TVTReference 记录(也在 VirtualTrees.pas 单元的接口部分中声明)包含一个指向从中拖动的实际 TBaseVirtualTree 对象的指针以及树所属进程的 ID。

因此,为了能够将树节点放到 TListBox 上,您必须执行以下操作:

  1. 写一个 class 来实现 IDropTarget interface (or use a pre-existing implementation, such as from Anders Melander's Drag&Drop suite).

  2. 使用 RegisterDragDrop().

  3. TListBox.Handle window 注册 class
  4. 在您的 IDropTarget 实现中,您可以查询提供的 IDataObject 以获取 CF_VIRTUALTREECF_VTREFERENCE 格式。如果成功,您的 Drop() 方法将可以访问正在拖动的树节点数据,并可以根据需要将其复制到 TListBox 中。

假设您的 TListBox 存在于与被拖出的 TVirtualStringTree 相同的进程中,我建议只关注 CF_VTREFERENCE,因为它是一种非常小且简单的格式(请参阅 TBaseVirtualTree.GetTreeFromDataObject() 方法的实现),当您可以通过源 TVirtualStringTree 直接代替。