1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
|
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\page dnd.html
\title Drag and Drop
\ingroup architecture
\brief An overview of the drag and drop system provided by Qt.
Drag and drop provides a simple visual mechanism which users can use
to transfer information between and within applications. (In the
literature this is referred to as a "direct manipulation model".) Drag
and drop is similar in function to the clipboard's cut and paste
mechanism.
\tableofcontents
This document describes the basic drag and drop mechanism and
outlines the approach used to enable it in custom widgets. Drag
and drop operations are also supported by Qt's item views and by
the graphics view framework; more information is available in the
\l{Using Drag and Drop with Item Views} and \l{The Graphics View
Framework} documents.
\section1 Configuration
The QApplication object provides some properties that are related
to drag and drop operations:
\list
\i \l{QApplication::startDragTime} describes the amount of time in
milliseconds that the user must hold down a mouse button over an
object before a drag will begin.
\i \l{QApplication::startDragDistance} indicates how far the user has to
move the mouse while holding down a mouse button before the movement
will be interpreted as dragging. Use of high values for this quantity
prevents accidental dragging when the user only meant to click on an
object.
\endlist
These quantities provide sensible default values for you to use if you
provide drag and drop support in your widgets.
\section1 Dragging
To start a drag, create a QDrag object, and call its
exec() function. In most applications, it is a good idea to begin a drag
and drop operation only after a mouse button has been pressed and the
cursor has been moved a certain distance. However, the simplest way to
enable dragging from a widget is to reimplement the widget's
\l{QWidget::mousePressEvent()}{mousePressEvent()} and start a drag
and drop operation:
\snippet doc/src/snippets/dragging/mainwindow.cpp 0
\dots 8
\snippet doc/src/snippets/dragging/mainwindow.cpp 2
Although the user may take some time to complete the dragging operation,
as far as the application is concerned the exec() function is a blocking
function that returns with \l{Qt::DropActions}{one of several values}.
These indicate how the operation ended, and are described in more detail
below.
Note that the exec() function does not block the main event loop.
For widgets that need to distinguish between mouse clicks and drags, it
is useful to reimplement the widget's
\l{QWidget::mousePressEvent()}{mousePressEvent()} function to record to
start position of the drag:
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 6
Later, in \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()}, we can determine
whether a drag should begin, and construct a drag object to handle the
operation:
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 7
\dots
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 8
This particular approach uses the \l QPoint::manhattanLength() function
to get a rough estimate of the distance between where the mouse click
occurred and the current cursor position. This function trades accuracy
for speed, and is usually suitable for this purpose.
\section1 Dropping
To be able to receive media dropped on a widget, call
\l{QWidget::setAcceptDrops()}{setAcceptDrops(true)} for the widget,
and reimplement the \l{QWidget::dragEnterEvent()}{dragEnterEvent()} and
\l{QWidget::dropEvent()}{dropEvent()} event handler functions.
For example, the following code enables drop events in the constructor of
a QWidget subclass, making it possible to usefully implement drop event
handlers:
\snippet doc/src/snippets/dropevents/window.cpp 0
\dots
\snippet doc/src/snippets/dropevents/window.cpp 1
\snippet doc/src/snippets/dropevents/window.cpp 2
The dragEnterEvent() function is typically used to inform Qt about the
types of data that the widget accepts.
You must reimplement this function if you want to receive either
QDragMoveEvent or QDropEvent in your reimplementations of
\l{QWidget::dragMoveEvent()}{dragMoveEvent()} and dropEvent().
The following code shows how dragEnterEvent() can be reimplemented to
tell the drag and drop system that we can only handle plain text:
\snippet doc/src/snippets/dropevents/window.cpp 3
The dropEvent() is used to unpack dropped data and handle it in way that
is suitable for your application.
In the following code, the text supplied in the event is passed to a
QTextBrowser and a QComboBox is filled with the list of MIME types that
are used to describe the data:
\snippet doc/src/snippets/dropevents/window.cpp 4
In this case, we accept the proposed action without checking what it is.
In a real world application, it may be necessary to return from the
dropEvent() function without accepting the proposed action or handling
the data if the action is not relevant. For example, we may choose to
ignore Qt::LinkAction actions if we do not support
links to external sources in our application.
\section2 Overriding Proposed Actions
We may also ignore the proposed action, and perform some other action on
the data. To do this, we would call the event object's
\l{QDropEvent::setDropAction()}{setDropAction()} with the preferred
action from Qt::DropAction before calling \l{QEvent::}{accept()}.
This ensures that the replacement drop action is used instead of the
proposed action.
For more sophisticated applications, reimplementing
\l{QWidget::dragMoveEvent()}{dragMoveEvent()} and
\l{QWidget::dragLeaveEvent()}{dragLeaveEvent()} will let you make
certain parts of your widgets sensitive to drop events, and give you more
control over drag and drop in your application.
\section2 Subclassing Complex Widgets
Certain standard Qt widgets provide their own support for drag and drop.
When subclassing these widgets, it may be necessary to reimplement
\l{QWidget::dragMoveEvent()}{dragMoveEvent()} in addition to
\l{QWidget::dragEnterEvent()}{dragEnterEvent()} and
\l{QWidget::dropEvent()}{dropEvent()} to prevent the base class from
providing default drag and drop handling, and to handle any special
cases you are interested in.
\section1 Drag and Drop Actions
In the simplest case, the target of a drag and drop action receives a
copy of the data being dragged, and the source decides whether to
delete the original. This is described by the \c CopyAction action.
The target may also choose to handle other actions, specifically the
\c MoveAction and \c LinkAction actions. If the source calls
QDrag::exec(), and it returns \c MoveAction, the source is responsible
for deleting any original data if it chooses to do so. The QMimeData
and QDrag objects created by the source widget \e{should not be deleted}
- they will be destroyed by Qt. The target is responsible for taking
ownership of the data sent in the drag and drop operation; this is
usually done by keeping references to the data.
If the target understands the \c LinkAction action, it should
store its own reference to the original information; the source
does not need to perform any further processing on the data. The
most common use of drag and drop actions is when performing a
Move within the same widget; see the section on \l{Drop Actions}
for more information about this feature.
The other major use of drag actions is when using a reference type
such as text/uri-list, where the dragged data are actually references
to files or objects.
\section1 Adding New Drag and Drop Types
Drag and drop is not limited to text and images. Any type of information
can be transferred in a drag and drop operation. To drag information
between applications, the applications must be able to indicate to each
other which data formats they can accept and which they can produce.
This is achieved using
\l{http://www.rfc-editor.org/rfc/rfc1341.txt}{MIME types}. The QDrag
object constructed by the source contains a list of MIME types that it
uses to represent the data (ordered from most appropriate to least
appropriate), and the drop target uses one of these to access the data.
For common data types, the convenience functions handle the MIME types
used transparently but, for custom data types, it is necessary to
state them explicitly.
To implement drag and drop actions for a type of information that is
not covered by the QDrag convenience functions, the first and most
important step is to look for existing formats that are appropriate:
The Internet Assigned Numbers Authority (\l{http://www.iana.org}{IANA})
provides a
\l{http://www.iana.org/assignments/media-types/}{hierarchical
list of MIME media types} at the Information Sciences Institute
(\l{http://www.isi.edu}{ISI}).
Using standard MIME types maximizes the interoperability of
your application with other software now and in the future.
To support an additional media type, simply set the data in the QMimeData
object with the \l{QMimeData::setData()}{setData()} function, supplying
the full MIME type and a QByteArray containing the data in the appropriate
format. The following code takes a pixmap from a label and stores it
as a Portable Network Graphics (PNG) file in a QMimeData object:
\snippet doc/src/snippets/separations/finalwidget.cpp 0
Of course, for this case we could have simply used
\l{QMimeData::setImageData()}{setImageData()} instead to supply image data
in a variety of formats:
\snippet doc/src/snippets/separations/finalwidget.cpp 1
The QByteArray approach is still useful in this case because it provides
greater control over the amount of data stored in the QMimeData object.
Note that custom datatypes used in item views must be declared as
\l{QMetaObject}{meta objects} and that stream operators for them
must be implemented.
\section1 Drop Actions
In the clipboard model, the user can \e cut or \e copy the source
information, then later paste it. Similarly in the drag and drop
model, the user can drag a \e copy of the information or they can drag
the information itself to a new place (\e moving it). The
drag and drop model has an additional complication for the programmer:
The program doesn't know whether the user wants to cut or copy the
information until the operation is complete. This often makes no
difference when dragging information between applications, but within
an application it is important to check which drop action was used.
We can reimplement the mouseMoveEvent() for a widget, and start a drag
and drop operation with a combination of possible drop actions. For
example, we may want to ensure that dragging always moves objects in
the widget:
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 7
\dots
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 8
The action returned by the exec() function may default to a
\c CopyAction if the information is dropped into another application
but, if it is dropped in another widget in the same application, we
may obtain a different drop action.
The proposed drop actions can be filtered in a widget's dragMoveEvent()
function. However, it is possible to accept all proposed actions in
the dragEnterEvent() and let the user decide which they want to accept
later:
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 0
When a drop occurs in the widget, the dropEvent() handler function is
called, and we can deal with each possible action in turn. First, we
deal with drag and drop operations within the same widget:
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 1
In this case, we refuse to deal with move operations. Each type of drop
action that we accept is checked and dealt with accordingly:
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 2
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 3
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 4
\dots
\snippet doc/src/snippets/draganddrop/dragwidget.cpp 5
Note that we checked for individual drop actions in the above code.
As mentioned above in the section on
\l{#Overriding Proposed Actions}{Overriding Proposed Actions}, it is
sometimes necessary to override the proposed drop action and choose a
different one from the selection of possible drop actions.
To do this, you need to check for the presence of each action in the value
supplied by the event's \l{QDropEvent::}{possibleActions()}, set the drop
action with \l{QDropEvent::}{setDropAction()}, and call
\l{QEvent::}{accept()}.
\section1 Drop Rectangles
The widget's dragMoveEvent() can be used to restrict drops to certain parts
of the widget by only accepting the proposed drop actions when the cursor
is within those areas. For example, the following code accepts any proposed
drop actions when the cursor is over a child widget (\c dropFrame):
\snippet doc/src/snippets/droprectangle/window.cpp 0
The dragMoveEvent() can also be used if you need to give visual
feedback during a drag and drop operation, to scroll the window, or
whatever is appropriate.
\section1 The Clipboard
Applications can also communicate with each other by putting data on
the clipboard. To access this, you need to obtain a QClipboard object
from the QApplication object:
\snippet examples/widgets/charactermap/mainwindow.cpp 3
The QMimeData class is used to represent data that is transferred to and
from the clipboard. To put data on the clipboard, you can use the
setText(), setImage(), and setPixmap() convenience functions for common
data types. These functions are similar to those found in the QMimeData
class, except that they also take an additional argument that controls
where the data is stored: If \l{QClipboard::Mode}{Clipboard} is
specified, the data is placed on the clipboard; if
\l{QClipboard::Mode}{Selection} is specified, the data is placed in the
mouse selection (on X11 only). By default, data is put on the clipboard.
For example, we can copy the contents of a QLineEdit to the clipboard
with the following code:
\snippet examples/widgets/charactermap/mainwindow.cpp 11
Data with different MIME types can also be put on the clipboard.
Construct a QMimeData object and set data with setData() function in
the way described in the previous section; this object can then be
put on the clipboard with the
\l{QClipboard::setMimeData()}{setMimeData()} function.
The QClipboard class can notify the application about changes to the
data it contains via its \l{QClipboard::dataChanged()}{dataChanged()}
signal. For example, we can monitor the clipboard by connecting this
signal to a slot in a widget:
\snippet doc/src/snippets/clipboard/clipwindow.cpp 0
The slot connected to this signal can read the data on the clipboard
using one of the MIME types that can be used to represent it:
\snippet doc/src/snippets/clipboard/clipwindow.cpp 1
\dots
\snippet doc/src/snippets/clipboard/clipwindow.cpp 2
The \l{QClipboard::selectionChanged()}{selectionChanged()} signal can
be used on X11 to monitor the mouse selection.
\section1 Examples
\list
\o \l{draganddrop/draggableicons}{Draggable Icons}
\o \l{draganddrop/draggabletext}{Draggable Text}
\o \l{draganddrop/dropsite}{Drop Site}
\o \l{draganddrop/fridgemagnets}{Fridge Magnets}
\o \l{draganddrop/puzzle}{Drag and Drop Puzzle}
\endlist
\section1 Interoperating with Other Applications
On X11, the public \l{http://www.newplanetsoftware.com/xdnd/}{XDND
protocol} is used, while on Windows Qt uses the OLE standard, and
Qt for Mac OS X uses the Carbon Drag Manager. On X11, XDND uses MIME,
so no translation is necessary. The Qt API is the same regardless of
the platform. On Windows, MIME-aware applications can communicate by
using clipboard format names that are MIME types. Already some
Windows applications use MIME naming conventions for their
clipboard formats. Internally, Qt uses QWindowsMime and
QMacPasteboardMime for translating proprietary clipboard formats
to and from MIME types.
On X11, Qt also supports drops via the Motif Drag & Drop Protocol. The
implementation incorporates some code that was originally written by
Daniel Dardailler, and adapted for Qt by Matt Koss <koss@napri.sk>
and Trolltech. Here is the original copyright notice:
\legalese
Copyright 1996 Daniel Dardailler.
Permission to use, copy, modify, distribute, and sell this software
for any purpose is hereby granted without fee, provided that the above
copyright notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting documentation,
and that the name of Daniel Dardailler not be used in advertising or
publicity pertaining to distribution of the software without specific,
written prior permission. Daniel Dardailler makes no representations
about the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
Modifications Copyright 1999 Matt Koss, under the same license as
above.
\endlegalese
\omit NOTE: The copyright notice is from qmotifdnd_x11.cpp. \endomit
Note: The Motif Drag \& Drop Protocol only allows receivers to
request data in response to a QDropEvent. If you attempt to
request data in response to e.g. a QDragMoveEvent, an empty
QByteArray is returned.
*/
/*!
\page porting4-dnd.html
\title Porting to Qt 4 - Drag and Drop
\contentspage {Porting Guides}{Contents}
\previouspage Porting to Qt 4 - Virtual Functions
\nextpage Porting .ui Files to Qt 4
\ingroup porting
\brief An overview of the porting process for applications that use drag and drop.
Qt 4 introduces a new set of classes to handle drag and drop operations
that aim to be easier to use than their counterparts in Qt 3. As a result,
the way that drag and drop is performed is quite different to the way
developers of Qt 3 applications have come to expect. In this guide, we
show the differences between the old and new APIs and indicate where
applications need to be changed when they are ported to Qt 4.
\tableofcontents
\section1 Dragging
In Qt 3, drag operations are encapsulated by \c QDragObject (see Q3DragObject)
and its subclasses. These objects are typically constructed on the heap in
response to mouse click or mouse move events, and ownership of them is
transferred to Qt so that they can be deleted when the corresponding drag and
drop operations have been completed. The drag source has no control over how
the drag and drop operation is performed once the object's
\l{Q3DragObject::}{drag()} function is called, and it receives no information
about how the operation ended.
\snippet doc/src/snippets/code/doc_src_dnd.qdoc 0
Similarly, in Qt 4, drag operations are also initiated when a QDrag object
is constructed and its \l{QDrag::}{exec()} function is called. In contrast,
these objects are typically constructed on the stack rather than the heap
since each drag and drop operation is performed synchronously as far as the
drag source is concerned. One key benefit of this is that the drag source
can receive information about how the operation ended from the value returned
by \l{QDrag::}{exec()}.
\snippet doc/src/snippets/porting4-dropevents/window.cpp 2
\snippet doc/src/snippets/porting4-dropevents/window.cpp 3
\dots 8
\snippet doc/src/snippets/porting4-dropevents/window.cpp 4
\snippet doc/src/snippets/porting4-dropevents/window.cpp 5
A key difference in the above code is the use of the QMimeData class to hold
information about the data that is transferred. Qt 3 relies on subclasses
of \c QDragObject to provide support for specific MIME types; in Qt 4, the
use of QMimeData as a generic container for data makes the relationship
between MIME type and data more tranparent. QMimeData is described in more
detail later in this document.
\section1 Dropping
In both Qt 3 and Qt 4, it is possible to prepare a custom widget to accept
dropped data by enabling the \l{QWidget::}{acceptDrops} property of a widget,
usually in the widget's constructor. As a result, the widget will receive
drag enter events that can be handled by its \l{QWidget::}{dragEnterEvent()}
function.
As in Qt 3, custom widgets in Qt 4 handle these events by determining
whether the data supplied by the drag and drop operation can be dropped onto
the widget. Since the classes used to encapsulate MIME data are different in
Qt 3 and Qt 4, the exact implementations differ.
In Qt 3, the drag enter event is handled by checking whether each of the
standard \c QDragObject subclasses can decode the data supplied, and
indicating success or failure of these checks via the event's
\l{QDragEnterEvent::}{accept()} function, as shown in this simple example:
\snippet doc/src/snippets/code/doc_src_dnd.qdoc 1
In Qt 4, you can examine the MIME type describing the data to determine
whether the widget should accept the event or, for common data types, you
can use convenience functions:
\snippet doc/src/snippets/porting4-dropevents/window.cpp 0
The widget has some control over the type of drag and drop operation to be
performed. In the above code, the action proposed by the drag source is
accepted, but
\l{Drag and Drop#Overriding Proposed Actions}{this can be overridden} if
required.
In both Qt 3 and Qt 4, it is necessary to accept a given drag event in order
to receive the corresponding drop event. A custom widget in Qt 3 that can
accept dropped data in the form of text or images might provide an
implementation of \l{QWidget::}{dropEvent()} that looks like the following:
\snippet doc/src/snippets/code/doc_src_dnd.qdoc 2
In Qt 4, the event is handled in a similar way:
\snippet doc/src/snippets/porting4-dropevents/window.cpp 1
It is also possible to extract data stored for a particular MIME type if it
was specified by the drag source.
\section1 MIME Types and Data
In Qt 3, data to be transferred in drag and drop operations is encapsulated
in instances of \c QDragObject and its subclasses, representing specific
data formats related to common MIME type and subtypes.
In Qt 4, only the QMimeData class is used to represent data, providing a
container for data stored in multiple formats, each associated with
a relevant MIME type. Since arbitrary MIME types can be specified, there is
no need for an extensive class hierarchy to represent different kinds of
information. Additionally, QMimeData it provides some convenience functions
to allow the most common data formats to be stored and retrieved with less
effort than for arbitrary MIME types.
*/
|