TDragDrop |
||
Description | |
TDragDrop is a
component for COM/OLE based drag&drop operations. The
component is able to make child-classes of TWinControl
(e.g. TEdit, TMemo, TListView, etc.) to be the source AND
target of drag&drop operations. Normally, you only use this component directly (for testing), if you develop an own drag&drop component based on this class. |
|
Important for Use | |
This file (index.htm) contains more information about restrictions, the disclaimer, remarks etc. | |
History | ||
Version 4.30 published on 17-Dec-1999 | ||
|
||
Version 4.20 published on 13-Nov-1999 | ||
|
||
Version 4.10 published on 06-Jul-1999 | ||
|
||
Version 4.00 published on 30-May-1999 | ||
|
||
Version 3.20 published on 3-May-1999 | ||
|
||
Version 3.11 published on 27-Feb-1999 | ||
|
||
Version 3.10 published on 19-Jan-1999 | ||
|
||
Version 3.00 updated on 31-Nov-1998 | ||
|
||
Version 2.01 published on 03-Oct-1998 | ||
|
||
Version 2.00 updated on 03-Oct-1998 | ||
|
||
Version 1.01 published on 12-Aug-1998 | ||
|
||
Version 1.00 published on 06-Aug-1998 | ||
|
||
Properties | |
AcceptOwnDnD published | |
If your DragDropControl is configured to be source AND target of drag&drop operations you can determine here, if your DragDropControl should accept its own drag&drop operation. This is important in example, if you want to change the order of Listbox items using this component and not the internal drag&drop operations. | |
AutoDetectDnD published | |
If your
DragDropControl is configured to be source of
drag&drop operations you can define here, if this
component should detect drag operations or not. The
property DragDetectDelta is involved in the detection.
IMPORTANT: If you use the drag-detection, it's high recommended to check the section "Problems With The Drag-Detection". |
|
BringToFront published | |
If the user has dropped data on the target control, you can determine here if the form should come to front after the drag&drop operation or not. | |
CHCopy public | |
Use this property to set a custom cursor for the copy-effect during drag&drop. | |
CHLink public | |
Use this property to set a custom cursor for the link-effect during drag&drop. | |
CHMove public | |
Use this property to set a custom cursor for the move-effect during drag&drop. | |
CHScrollCopy public | |
Use this property to set a custom cursor for the copy-effect during drag&drop and scrolling in the target window. | |
CHScrollLink public | |
Use this property to set a custom cursor for the link-effect during drag&drop and scrolling in the target window. | |
CHScrollMove public | |
Use this property to set a custom cursor for the move-effect during drag&drop and scrolling in the target window. | |
DragDetectDelta published | |
Is the drag detection enabled by AutoDetectDnD or calling StartDnDDetection, the drag detection was successful, if the mouse was moved over more than in this property defined pixels. | |
DragDropControl published | |
Choose
here a component like Listbox etc. that should be handled
as source and target for drag&drop operations.
IMPORTANT: If you use the drag-detection, it's high recommended to check the section "Problems With The Drag-Detection". |
|
OwnerIsSource public, read-only | |
This property indicates during a drag&drop operation, if the DragDropControl is the source of the d&d-operation or not. | |
Registered public, read-only | |
You can determine here, if the DragDropControl is registered as target of drag&drop operations or not. | |
RenderOn published | |
You can
determine here, when the dropped data should be rendered
(only important for the inherited classes). If it is set to rdoDropSync, the data is rendered before calling the event-handler OnDrop. If it is set to rdoDropAsync, the data is rendered before calling the event-handler OnProcessDropped. If it is set to rdoEnter, the data is rendered before calling the event-handler OnDragEnter. If it is set to rdoEnterAndDropSync, the data is rendered before calling the event-handler OnDragEnter AND before calling the event-handler OnDrop (yes two times - in some cases it's necessary). If it is set to rdoEnterAndDropAsync, the data is rendered before calling the event-handler OnDragEnter AND before calling the event-handler OnProcessDropped (yes two times - in some cases it's necessary). If it is set to rdoNever, the data is never rendered. Normally, you never need this value - it makes only sense for application-internal drag&drop (the application knows the data; why should we spend our precious time on rendering the known data?) Be careful, if you set this property to rdoDropAsync, rdoDropEnterAndDropSync, rdoDropEnterAndDropAsync or rdoEnter, because the OLE2 Drag&Drop isn't correctly implemented in every program. On testing (high recommend!!!), you will be surprised, how many well-known programs make trouble because of wrong implemention. |
|
ScrollDetectOptions published | |
This
property has many sub-properties:
AreaBottom, AreaLeft, AreaRight, AreaTop have the sub-properties Margin, Range. You can determine with Margin where the scroll-detect-area begins, measured from the clientarea-border. You can determine with Range the width resp. height of the scroll-detect-area. The properties AreaBottom and AreaTop are used for the vertical scroll detection, AreaLeft and AreaRight for the horizontal detection. HorzScrolling and VertScrolling are further sub-properties under ScrollDetectOptions. You can enable/disable the scroll detection with these properties. HorzPageScroll and VertPageScroll are even further sub-properties under ScrollDetectOptions. You can switch here between line or page scrolling. ScrollDelay is even a sub-property under ScrollDetectOptions. You can determine with property the delay time to the next scroll event in the DragDropControl. StartDelay is even a further sub-property under ScrollDetectOptions. You can determine with property the delay time till the first scroll event is sent to the DragDropControl. The scroll-detection does only work, if at least one TargetEffect is set. |
|
SourceCompatibility published | |
This property was added due to incompatible implemention of drag&drop in other applications. They set some value incorrectly in the FormatEtc record, because these values aren't used for the dragged format. With this property you can determine, if you don't to check these values for a successful drag&drop. If you disable a check, you take risk to drop data in a invalid format. Normally, you need not to switch this property. | |
SourceEffects published | |
Choose
the effects that the DragDropControl should support. If you don't want
that the DragDropControl serve as drag&drop source all
items must be false. IMPORTANT: If you use the drag-detection, it's high recommended to check the section "Problems With The Drag-Detection". |
|
TargetEffects published | |
Choose the effects that the DragDropControl should support. If you don't want that the DragDropControl serve as drag&drop target, all items must be false. | |
TargetPopUpMenu published | |
Here you determine, if should the popup-menu get visible when a drag&drop operations occurs with pressing the right mouse button or not. (Important, if the DragDropControl is configured as drag&drop target!!!) | |
Events | |
OnBeforeScrolling published | |
This event is called before a scroll-event is sent to the DragDropControl. The scroll-detection must be enabled for this event. | |
OnAfterScrolling published | |
This event is called after a scroll-event is sent to the DragDropControl. The scroll-detection must be enabled for this event. | |
OnDragDetect published | |
Is
called on starting (parameter DragStatus=ddsLeft
or ddsRight, depends which mousebutton is
pressed), on starting the drag (DragStatus=ddsDrag),
on finishing the detection (DragStatus=ddsNone)
and cancelling the detection (DragStatus=ddsCancelled).
If DragStatus=ddsDrag, the
drag&drop operation won't be started automatically.
If you want to start drag&drop, you must call Execute on yourself. The parameters DetectStartX
and DetectStartY specify the cursor
position, where the detection has started. The parameters
x and y specify the current
position of the cursor. IMPORTANT: If you use the drag-detection, it's high recommended to check the section "Problems With The Drag-Detection". |
|
OnDragEnter published | |
Is called, when the DragDropControl is a target of drag&drop operations. The mouse cursor moves ON (one call only) the DragDropControl. Here, you influence if a drop can be accepted and the drop's effect if accepted. | |
OnDragLeave published | |
Is called, when the DragDropControl is a target of drag&drop operations. The mouse cursor leaves the DragDropControl (one call only) or the drag&drop operation is cancelled. | |
OnDragOver published | |
Is called, when the DragDropControl is a target of drag&drop operations. The mouse cursor moves OVER (called on every mouse move) the DragDropControl. Even here, you can influence if a drop can be accepted and the drop's effect if accepted. Because this function is very often called, YOUR method should be programmed very efficient. | |
OnDrop published | |
Is triggered, when the DragDropControl is the target of drag&drop operations. It instructs the DragDropControl to handle the data which are dropped on it. Save here only the dropped data (, if this isn't done by the child-class), because the source of the drag&drop operation isn't accessable any longer as soon as this event-method was left. For processing the data in a child-class, it's high recommend to use OnProcessDropped. | |
OnDropHandlerSucceeded protected | |
Is triggered, if
the DropHandler was successfully called and executed. Also check the section: "Details about the DropHandler". |
|
OnGiveFeedback published | |
Is called, when the DragDropControl is the source of drag&drop operations. It enables the source application to give visual feedback to its end user during a drag&drop operation by providing the OLE DoDragDrop function with an enumeration value specifying the visual effect. Mostly you don't need this event. | |
OnMenuDestroy protected | |
Is triggered,
when the context-menu and its items are going to be
destroyed. This event important for you, if you have add
custom items to the menu. Also check the section: "Details about the context-menu". |
|
OnMenuExecCmd protected | |
Is triggered,
when a custom item was selected in the context-menu by
the user. Now, you should execute the routines etc, which
are linked with the selected menuitem. Also check the section: "Details about the context-menu". |
|
OnMenuPopup protected | |
Is triggered,
when the context-menu is going to popup. Also check the section: "Details about the context-menu". |
|
OnMenuSucceeded protected | |
Is triggered,
when the routines etc, which are linked with the selected
menuitem, were successfully executed. Also check the section: "Details about the context-menu". |
|
OnProcessDropped published | |
Is called after OnDrop by a self sended message with "PostMessage". This has the effect, that the user can access to the source of the drag&drop operation during you process the dropped data. Of course, you must save the dropped data in OnDrop. In my child-classes you haven't care about this. | |
OnQueryContinueDrag published | |
Is called, when the DragDropControl is a source of drag&drop operations. You can determine whether the drag&drop operation should be continued, cancelled, or completed. You do not call this method directly. The OLE DoDragDrop function calls this method during a drag-and-drop operation. Mostly, you don't need this event. | |
Methods | |
CopyToClipboard public | |
Call this method, if you want to copy your data to the clipboard. | |
DoMenuDestroy protected | |
Never call the
method directly - it is called by this component itself.
This method has the same purpose as the event OnMenuDestroy. You can use this method for inherited
classes. Also check the section: "Details about the context-menu". |
|
DoMenuExecCmd protected | |
Never call the
method directly - it is called by this component itself.
This method has the same purpose as the event OnMenuExecCmd. You can use this method for inherited
classes. Also check the section: "Details about the context-menu". |
|
DoMenuPopup protected | |
Never call the
method directly - it is called by this component itself.
This method has the same purpose as the event OnMenuPopup. You can use this method for inherited
classes. Also check the section: "Details about the context-menu". |
|
DropHandler protected | |
Never call the
method directly - it is called by this component itself.
Inherit this method for implementing custom
drop-handlers. Also check the section: "Details about the DropHandler". |
|
Execute public | |
Call
this method, if you detect that the user wants to start a
drag&drop operation (e.g. MouseDown). Before calling,
you have to create a valid IDataObject (for more
informations, look over the source of the components
"TDragDropFiles" or
"TDragDropFiles"). IMPORTANT: If you use the drag-detection, it's high recommended to check the section "Problems With The Drag-Detection". |
|
ExecuteOperation public | |
This method is called by Execute. Normally, you don't call this method directly. | |
GetFromClipboard public | |
Call this method, if you want to get data from the clipboard. This will only succeed, if the data formats are supported. | |
StartDnDDetection public | |
Call this method, if you want to start the drag detection manually. Normally, you call this method in the OnMouseDown event. | |
Constants | |
DropEffect_None, DropEffect_Copy, DropEffect_Move, DropEffect_Link, DropEffect_Scroll | |
These constants describe the kind of drop effect the user want to have. These values are used by the parameter dwEffect of methods. DropEffect_Scroll indicates a scrolling context of the drop target. | |
How Do I Use It As Drag&Drop Source | ||
1. | Drop a TWinControl on the form (e.g. a listbox). | |
2. | Choose the TWinControl (listbox) in DragDropControl. | |
3. | Choose the drag&drop effects under SourceEffects that the DragDropControl (listbox) should support. If you don't want any longer that the DragDropControl serve as drag&drop source all items must be set to false. | |
4. | Now, your DragDropControl (listbox) must detect, if the user wants to start a drag&drop operation. You can use the event "OnMouseDown" of your DragDropControl (listbox). You must create a DataObject. If you have no idea, how to do that, look over the source of the component TDragDropFiles or TDragDropText. | |
5. | Tell Windows that there is a drag&drop operation to handle: Just call the method ExecuteOperation of this component (for child-classes: call Execute). Now, windows handles the drag&drop operation. | |
6. | You may use the events OnGiveFeedback and OnQueryContinueDrag, but often you need not. | |
Hints: | ||
|
||
How Do I Use It As Drag&Drop Target | ||
1. | Drop a TWinControl on the form (e.g. a listbox). | |
2. | Choose the TWinControl (listbox) in DragDropControl. | |
3. | Choose the drag&drop effects under TargetEffects that the DragDropControl (listbox) should support. If you don't want any longer that the DragDropControl serve as drag&drop target all items must be set to false. | |
4. | Now, you have to program what happen, when the user drops a bitmap on your DragDropControl (listbox). For this, the best is to use the event OnDrop (or OnProcessDropped in the child-class; but only there!). At first, you should check what drag&drop effect was chosen by the user. You get the effect from method's parameter dwEffect. | |
5. | You may use the events OnDragEnter, OnDragOver and OnDragLeave, but often you need not. | |
Hints: | ||
|
||
Some Important Hints | |
|
|
How To Build An Own Child-Class | ||
Before you
build your own child-class, it's very useful to
understand the mechanism of drag&drop. Graham Wideman
has written some very good documents with diagrams! It's
high recommended to visit his site: http://www.wideman-one.com. Use my "Drag&Drop-Analyser" for testing & analysing the dropped data. You can use it as target of drag&drop operations. It gives informations about the dropped data. You have not to do much, if you build a child-class like TDragDropFiles or TDragDropText. You must only build a child-class from TEnumFormatEtc, TDataObject and TDragDrop. and override the following methods, the rest of the work, I've already done:
|
||
Details about the context-menu | |
With the context-menu are
following properties, events and methods involved: TargetPopUpMenu, OnMenuDestroy, OnMenuExecCmd, OnMenuPopup, OnMenuSucceeded, DoMenuDestroy, DoMenuExecCmd and DoMenuPopup. The context-menu does only
appear, if TargetPopUpMenu is set to true and the data is
dragged with the right mousebutton. Override the methods
(DoXXXXXXX ), if you write a
custom component based on TDragDrop
otherwise use the events (OnXXXXXXX). The order of the called methods/events after a drop is as following: First, xxMenuPopup (the "xx" stand for "Do" and "On") is called. You implement in xxMenuPopup your custom menuitems. Here is an example:
If you override the method DoMenuPopup, you also must call:
You find more information on adding items to a popup-menu in the Win32-help. Look for "InsertMenuItem". If you add more items, you must increase AMinCustCmd for every new item, to identify the items later! Of course, you must remember the ID to all items or you don't know, which item was selected! xxMenuExecCmd is only called, if it was detected, that one of your custom menuitems was selected. Now, you have to executed the routines etc, which are linked with the selected menuitem. Here the continue of the example:
Don't forget to set the parameter Succeeded. Set only the value to true after the routine was successfully executed. If you override the method DoMenuExecCmd, you also must call the inherited method! xxMenuSucceeded is only called, if the routines in xxMenuExecCmd were successfully executed. This notification is helpful, if you must update the display after successful update. If you override the method DoMenuSucceeded, you also must call the inherited method! xxMenuDestroy is called after all. Now, it's time to de-intialize everything what you've initialized in xxMenuPopup. Here the continue of the example:
If you override the method DoMenuDestroy, you also must call the inherited method! |
|
Details about the DropHandler | |
The method DropHandler was implemented to allow alternative handling of the dropped data. This is especially important for implementing shell extentions. Was a drophandler successfully called, the event OnDropHandlerSucceeded is triggered. You can only use the the DropHandler only, if you inherit the class TDragDrop. Mostly, the coding in the method DropHandler is nearly similar with that in the method RenderDropped. First, you will render the dropped data, then you will handle the data. You don't do more in this method, and you cannot do more! | |
FAQ | |
Q: I want a single
component to be the target of more than one type of drag,
what can I do? One always overrides the other. If I use
the TDragDrop, where is the information about what was
dropped? A: You've to write your own child-class from TDragDrop. But you can copy the most of my child-classes together, for faster developing your class. You can't access the dropped data directly. For this you have the class TDataObject (look at params of methods ...). You have format description for every data(-set) in your data object . You can enumerate the available formats with EnumFormatEtc. With "QueryGetData" you can check, if a special format is available. The data itself you can get with "GetData". Because of my components design you should better use my new introduced method "RenderData". I hope, it helps a little bit. Don't be disappointed, if you don't understand drag&drop immediately. I've even needed some months to understand the mechanisms completely. |
|
Problems With The Drag-Detection | |
I got reports, that some controls
e.g. listboxes or grids make trouble in some situations
with the drag-detection. This behaviour results of a to
old or just incompatible implementation of events in the
controls. In such a case you must write a workaround.
Mostly, following helps:
In some cases e.g. with grids this doesn't work. In these cases you must do a little bit more, as I show you the demo "GridFixDemo.zip". Mostly, the workaround isn't really difficult to write. |
|
Known Bugs | |
|
|
© 1998,99 by Dieter Steinwedel
Back to index