Is it possible to drag and drop nodes from TVirtualStringTree
into a VCL control when the DragType
is set to dtOLE
(not dtVCL
)
I have a situation where I need to be able to drag nodes from one VT to another VT (dtOLE
works fine), but at the same time, while dragging, I need an option to be able to drop the nodes into a TListBox
(or other VCL control).
I tried setting DragAcceptFiles()
API for the TListBox
handle, but it had no effect.
How can it be done?
There is no DragAcceptFiles
property on TListBox
. If you mean that you are calling the Win32 API DragAcceptFiles()
function on the TListBox.Handle
window, that would only work if:
you manually subclass the TListBox.WindowProc
property to handle the WM_DROPFILES
window message.
TVirtualStringTree
provides the CF_HDROP
format during OLE dragging.
2 is not true, though. CF_HDROP
is meant only for dragging filesystem paths, which is not what TVirtualStringTree
drags. So using DragAcceptFiles()
is out.
TVirtualStringTree
(and other TBaseVirtualTree
descendants) uses custom data formats during OLE dragging (the interface section of the VirtualTrees.pas
unit declares these format IDs, so you do not need to register them manually in your own code):
CF_VIRTUALTREE
contains an IStream
or HGLOBAL
holding a serialized form of the selected tree nodes that are being dragged. The serialization is comprised of a series of data chunks describing each node. You will have to refer to the implementation of the VirtualTree.pas
unit to decipher this format (I'm not going to do it here).
CF_VTREFERENCE
contains an HGLOBAL
holding a TVTReference
record (which is also declared in the interface section of the VirtualTrees.pas
unit) containing a pointer to the actual TBaseVirtualTree
object that is being dragged from and the ID of the process that the tree belongs to.
So, in order for you to be able to drop tree nodes onto the TListBox
, you will have to do the following:
write a class that implements the IDropTarget
interface (or use a pre-existing implementation, such as from Anders Melander's Drag&Drop suite).
register that class with the TListBox.Handle
window using RegisterDragDrop()
.
in your IDropTarget
implementation, you can query the provided IDataObject
for the CF_VIRTUALTREE
and CF_VTREFERENCE
formats. If successful, your Drop()
method will have access to the tree node data that is being dragged and can copy it into the TListBox
as needed.
Assuming your TListBox
exists in the same process as the TVirtualStringTree
being dragged from, I would suggest focusing on just CF_VTREFERENCE
, since it is a very small and simple format (see the implementation of the TBaseVirtualTree.GetTreeFromDataObject()
method), and parsing the CF_VIRTUALTREE
data would be overkill (see the implementation of the TBaseVirtualTree.ProcessOLEData()
method) when you can just enumerate through the source TVirtualStringTree
directly instead.