1998-05-22 15:57:05 -04:00
|
|
|
Drag-and-Drop Support in wxWindows
|
|
|
|
==================================
|
|
|
|
|
|
|
|
1. Overview
|
|
|
|
--------
|
|
|
|
|
|
|
|
a) What is it?
|
|
|
|
|
|
|
|
We're calling drag-and-drop (or d&d for short) the OLE mechanism of data
|
|
|
|
transfer. Please note that it's not the same thing as the file oriented d&d
|
|
|
|
of Windows 3.1 "File Manager" which is designed for and limited to the file
|
|
|
|
names only.
|
|
|
|
|
|
|
|
OLE d&d allows application to transfer data of any type to the same or
|
|
|
|
another process.
|
|
|
|
|
|
|
|
|
|
|
|
b) How is it done? (user's point of view)
|
|
|
|
|
|
|
|
To start a d&d operation the user presses the mouse button 1 (left) and
|
|
|
|
drags the selected object to another window (which must be at least partially
|
|
|
|
visible on the screen) or to an icon on the taskbar in which case the
|
|
|
|
corresponding window will be automatically restored. To finish the operation,
|
|
|
|
the user releases the button. Default d&d operation is "move", but several key
|
|
|
|
act as modifiers: keeping down the <Ctrl> key at the moment of drop does
|
|
|
|
"copy", while <Shift> or <Alt> force the "move" (makes sense if default isn't
|
|
|
|
"move").
|
|
|
|
|
|
|
|
|
|
|
|
c) How is it done? (programmer's point of view)
|
|
|
|
|
|
|
|
There are several objects participating in a d&d operation. First of all,
|
|
|
|
there is the data object itself. Second, there is the drop source which is
|
|
|
|
responsible for creating the data object (if it doesn't exist yet) and starting
|
2011-03-22 10:17:38 -04:00
|
|
|
the d&d operation. Finally, the drop target receives the notification when
|
1998-05-22 15:57:05 -04:00
|
|
|
the data is dropped onto the associated window (see below) and is responsible
|
|
|
|
for pasting the data and returning the result code (copy, move or failure).
|
|
|
|
There is one class for each one of these roles in wxWindows d&d implementation,
|
|
|
|
plese see their descriptions below for details.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. Drop Target
|
|
|
|
-----------
|
|
|
|
|
|
|
|
a) Being a drop target
|
|
|
|
|
|
|
|
... is as easy as deriving your window class from wxDropTarget and
|
|
|
|
associating it with a wxWindow object (or perhaps some wxWindow-derived class,
|
|
|
|
such as wxFrame). The pure virtual function wxDropTarget::OnDrop() must be
|
|
|
|
implemented in your application and will be called whenever the mouse button
|
|
|
|
is released over the window in question. Other virtual functions that will be
|
|
|
|
called in the process of the d&d operation are OnEnter and OnLeave.
|
|
|
|
|
|
|
|
@@ should OnDragOver() be user overridable also?
|
|
|
|
|
|
|
|
You should associate wxDropTarget and wxWindow calling SetDropTarget:
|
|
|
|
wxWindow *pWindow = GetTopWindow();
|
|
|
|
pWindow->SetDropTarget(new MyDropTarget);
|
|
|
|
|
|
|
|
The object created passed to SetDropTarget becomes the propriety of wxWindow
|
|
|
|
and will be deleted with the window (or when you call SetDropTarget next
|
|
|
|
time). You can always break the association by calling SetDropTarget(NULL).
|
|
|
|
|
|
|
|
When some data is dragged over a window, the program must decide if it's
|
|
|
|
going to accept this data or not. The virtual function IsAcceptedData() is
|
|
|
|
called to do it. The default implementation takes care of OLE interface
|
|
|
|
pointer manipulations and only requires you to override GetCountFormats()
|
|
|
|
and GetFormat(n) functions to let it know what data formats you support.
|
|
|
|
If it's not flexible enough for your application (i.e. the set of supported
|
|
|
|
formats changes over time...), you should override IsAcceptedData(). In 99%
|
|
|
|
of cases the default implementation is ok and you only have to return count
|
|
|
|
of supported formats (CF_xxx constants or one of your custom formats which
|
|
|
|
must have been registered) and their values.
|
|
|
|
|
|
|
|
b) OnDrop(long x, long y, const void *pData)
|
|
|
|
|
|
|
|
(x, y) are drop point (client) coordinates, pData is the pointer to data
|
|
|
|
(whatever it is).
|
|
|
|
|
|
|
|
If 'true' is returned from OnDrop, the operation is considered to be
|
|
|
|
successful and the corresponding code (MOVE or COPY depending on the
|
|
|
|
keyboard control keys) is returned. Otherwise, the operation is cancelled.
|
|
|
|
|
|
|
|
Please remember that returning 'true' here may mean 'move' and so the
|
|
|
|
drop source will delete the corresponding data - which would lead to
|
|
|
|
data loss if you didn't paste it properly.
|
|
|
|
|
|
|
|
c) OnEnter()
|
|
|
|
|
|
|
|
called when the mouse enters the window: you might use this function to
|
|
|
|
give some additional visual feedback.
|
|
|
|
|
|
|
|
d) OnLeave()
|
|
|
|
|
|
|
|
called when the mouse leaves the window; might be a good place to clean
|
|
|
|
up things allocated in OnEnter.
|
|
|
|
|
|
|
|
e) Simple wxDropTarget specializations
|
|
|
|
|
|
|
|
Two (very simple) wxDropTarget-derived classes are provided for two most
|
|
|
|
common situations: d&d of text and file d&d. To use them you only need to
|
|
|
|
override one virtual function OnDropText in wxTextDropTarget's case and
|
|
|
|
OnDropFiles for wxFileDropTarget.
|
|
|
|
|
|
|
|
The (x, y) are the same as for OnDrop() function. OnDropText's last
|
|
|
|
parameter points to a (always ANSI, not Unicode) text string, while
|
|
|
|
OnDropFiles() parameter is the array of file names just dropped (and the
|
|
|
|
count of them is passed in the 3rd parameter).
|
|
|
|
|
|
|
|
3. Data Object
|
|
|
|
-----------
|
|
|
|
|
|
|
|
a) Drag and drop and clipboard
|
|
|
|
|
|
|
|
The effect of a d&d operation is the same as using the clipboard to
|
|
|
|
cut/copy and paste data and it would be nice to use the same code to implement
|
|
|
|
these two data transfer mechanisms. The wxDataObject allows you to do exactly
|
|
|
|
this. It encapsulates the data which can be passed either through the clipboard
|
|
|
|
or d&d.
|
|
|
|
|
|
|
|
|
|
|
|
b) Data format
|
|
|
|
|
|
|
|
There are several standard clipboard formats, such as text, bitmap or
|
|
|
|
metafile picture. All of them are defined in wxDataObject::StdFormats
|
|
|
|
enumeration. Of course, it's not always enough and you'll often need your
|
|
|
|
own format for data transfer. The simple helper class wxDataFormat may help
|
|
|
|
you: when you create an object of this class, it registers a new clipboard
|
|
|
|
data format identified by the string passed to it's ctor.
|
|
|
|
|
|
|
|
After your new format is registered, you may use it as any other one.
|
|
|
|
|
|
|
|
4. Drop Source
|
|
|
|
-----------
|
|
|
|
|
|
|
|
a) Starting the d&d operation
|
|
|
|
|
|
|
|
In order to start the d&d operation you should call the DoDragDrop function
|
|
|
|
(typically in reply to a "mouse button press" message). NB: DoDragDrop() is a
|
|
|
|
blocking function which enters into it's own message loop and may return after
|
|
|
|
an arbitrarily long time interval. During it, the QueryContinueDrag() is called
|
|
|
|
whenever the mouse or keyboard state changes. The default behaviour is quite
|
|
|
|
reasonable for 99% of cases: the drag operation is cancelled if the <Esc> key
|
|
|
|
is preessed and the drop is initiated if the mouse button is released.
|
|
|
|
|
|
|
|
b) After the end of d&d
|
|
|
|
|
|
|
|
The drop source behaviour depends on DoDragDrop() return code. If it
|
|
|
|
returns wxDropSource::None or wxDropSource::Copy there is normally nothing to
|
|
|
|
do, but you shouldn't forget to delete your data if it returns the
|
|
|
|
wxDropSource::Move code.
|
|
|
|
|
|
|
|
c) DoDragDrop
|
|
|
|
|
|
|
|
d) QueryContinueDrag
|
|
|
|
|
|
|
|
|
|
|
|
5. Remarks
|
|
|
|
-------
|
|
|
|
|
|
|
|
|
|
|
|
@@@@ TODO: support tymed != TYMED_HGLOBAL;
|
|
|
|
better support of CF_BMP, CF_METAFILE
|
|
|
|
scrolling support!! (how?)
|
|
|
|
sample demonstrating use of user-defined formats
|
|
|
|
sample which really does something useful
|