source: trunk/doc/src/examples/fridgemagnets.qdoc@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 16.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \example draganddrop/fridgemagnets
44 \title Fridge Magnets Example
45
46 The Fridge Magnets example shows how to supply more than one type
47 of MIME-encoded data with a drag and drop operation.
48
49 \image fridgemagnets-example.png
50
51 With this application the user can play around with a collection
52 of fridge magnets, using drag and drop to form new sentences from
53 the words on the magnets. The example consists of two classes:
54
55 \list
56 \o \c DragLabel is a custom widget representing one
57 single fridge magnet.
58 \o \c DragWidget provides the main application window.
59 \endlist
60
61 We will first take a look at the \c DragLabel class, then we will
62 examine the \c DragWidget class.
63
64 \section1 DragLabel Class Definition
65
66 Each fridge magnet is represented by an instance of the \c
67 DragLabel class:
68
69 \snippet examples/draganddrop/fridgemagnets/draglabel.h 0
70
71 Each instance of this QLabel subclass will be used to display an
72 pixmap generated from a text string. Since we cannot store both
73 text and a pixmap in a standard label, we declare a private variable
74 to hold the original text, and we define an additional member
75 function to allow it to be accessed.
76
77 \section1 DragLabel Class Implementation
78
79 In the \c DragLabel constructor, we first create a QImage object
80 on which we will draw the fridge magnet's text and frame:
81
82 \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 0
83
84 Its size depends on the current font size, and its format is
85 QImage::Format_ARGB32_Premultiplied; i.e., the image is stored
86 using a premultiplied 32-bit ARGB format (0xAARRGGBB).
87
88 We then construct a font object that uses the application's
89 default font, and set its style strategy. The style strategy tells
90 the font matching algorithm what type of fonts should be used to
91 find an appropriate default family. The QFont::ForceOutline forces
92 the use of outline fonts.
93
94 To draw the text and frame onto the image, we use the QPainter
95 class. QPainter provides highly optimized methods to do most of
96 the drawing GUI programs require. It can draw everything from
97 simple lines to complex shapes like pies and chords. It can also
98 draw aligned text and pixmaps.
99
100 \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 1
101
102 A painter can be activated by passing a paint device to the
103 constructor, or by using the \l{QPainter::}{begin()} method as we
104 do in this example. The \l{QPainter::}{end()} method deactivates
105 it. Note that the latter function is called automatically upon
106 destruction when the painter is actived by its constructor. The
107 QPainter::Antialiasing render hint ensures that the paint engine
108 will antialias the edges of primitives if possible.
109
110 When the painting is done, we convert our image to a pixmap using
111 QPixmap's \l {QPixmap::}{fromImage()} method. This method also
112 takes an optional flags argument, and converts the given image to
113 a pixmap using the specified flags to control the conversion (the
114 flags argument is a bitwise-OR of the Qt::ImageConversionFlags;
115 passing 0 for flags sets all the default options).
116
117 \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 2
118
119 Finally, we set the label's \l{QLabel::pixmap}{pixmap property}
120 and store the label's text for later use.
121
122 \e{Note that setting the pixmap clears any previous content, including
123 any text previously set using QLabel::setText(), and disables
124 the label widget's buddy shortcut, if any.}
125
126 \section1 DragWidget Class Definition
127
128 The \c DragWidget class inherits QWidget, providing support for
129 drag and drop operations:
130
131 \snippet examples/draganddrop/fridgemagnets/dragwidget.h 0
132
133 To make the widget responsive to drag and drop operations, we simply
134 reimplement the \l{QWidget::}{dragEnterEvent()},
135 \l{QWidget::}{dragMoveEvent()} and \l{QWidget::}{dropEvent()} event
136 handlers inherited from QWidget.
137
138 We also reimplement \l{QWidget::}{mousePressEvent()} to make the
139 widget responsive to mouse clicks. This is where we will write code
140 to start drag and drop operations.
141
142 \section1 DragWidget Class Implementation
143
144 In the constructor, we first open the file containing the words on
145 our fridge magnets:
146
147 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 0
148
149 QFile is an I/O device for reading and writing text and binary
150 files and resources, and may be used by itself or in combination
151 with QTextStream or QDataStream. We have chosen to read the
152 contents of the file using the QTextStream class that provides a
153 convenient interface for reading and writing text.
154
155 We then create the fridge magnets. As long as there is data (the
156 QTextStream::atEnd() method returns true if there is no more data
157 to be read from the stream), we read one line at a time using
158 QTextStream's \l {QTextStream::}{readLine()} method.
159
160 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 1
161
162 For each line, we create a \c DragLabel object using the read line
163 as text, we calculate its position and ensure that it is visible by
164 calling the QWidget::show() method. We set the Qt::WA_DeleteOnClose
165 attribute on each label to ensure that any unused labels will be
166 deleted; we will need to create new labels and delete old ones when
167 they are dragged around, and this ensures that the example does not
168 leak memory.
169
170 We also set the \c FridgeMagnets widget's palette, minimum size
171 and window title.
172
173 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 2
174
175 Finally, to enable our user to move the fridge magnets around, we
176 must also set the \c FridgeMagnets widget's
177 \l{QWidget::acceptDrops}{acceptDrops} property.
178
179 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 3
180
181 Setting this property to true announces to the system that this
182 widget \e may be able to accept drop events (events that are sent
183 when drag and drop actions are completed). Later, we will
184 implement the functions that ensure that the widget accepts the
185 drop events it is interested in.
186
187 \section2 Dragging
188
189 Let's take a look at the \l{QWidget::}{mousePressEvent()} event
190 handler, where drag and drop operations begin:
191
192 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 13
193 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 14
194
195 Mouse events occur when a mouse button is pressed or released
196 inside a widget, or when the mouse cursor is moved. By
197 reimplementing the \l{QWidget::}{mousePressEvent()} method we
198 ensure that we will receive mouse press events for the widget
199 containing the fridge magnets.
200
201 Whenever we receive such an event, we first check to see if the
202 position of the click coincides with one of the labels. If not,
203 we simply return.
204
205 If the user clicked a label, we determine the position of the
206 \e{hot spot} (the position of the click relative to the top-left
207 corner of the label). We create a byte array to store the label's
208 text and the hot spot, and we use a QDataStream object to stream
209 the data into the byte array.
210
211 With all the information in place, we create a new QMimeData object.
212 As mentioned above, QMimeData objects associate the data that they
213 hold with the corresponding MIME types to ensure that information
214 can be safely transferred between applications. The
215 \l{QMimeData::}{setData()} method sets the data associated with a
216 given MIME type. In our case, we associate our item data with the
217 custom \c application/x-fridgemagnet type.
218
219 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 15
220
221 Note that we also associate the magnet's text with the
222 \c text/plain MIME type using QMimeData's \l{QMimeData::}{setText()}
223 method. Below, we will see how our widget detects both these MIME
224 types with its event handlers.
225
226 Finally, we create a QDrag object. It is the QDrag class that
227 handles most of the details of a drag and drop operation,
228 providing support for MIME-based drag and drop data transfer. The
229 data to be transferred by the drag and drop operation is contained
230 in a QMimeData object. When we call QDrag's
231 \l{QDrag::}{setMimeData()} method the ownership of our item data is
232 transferred to the QDrag object.
233
234 We call the \l{QDrag::}{setPixmap()} function to set the pixmap used
235 to represent the data during the drag and drop operation.
236 Typically, this pixmap shows an icon that represents the MIME type
237 of the data being transferred, but any pixmap can be used. In this
238 example, we simply use the pixmap used by the label itself to make
239 it look like the fridge magnet itself is being moved.
240
241 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 16
242
243 We also specify the cursor's hot spot, its position relative to the
244 top-level corner of the drag pixmap, to be the point we calculated
245 above. This makes the process of dragging the label feel more natural
246 because the cursor always points to the same place on the label
247 during the drag operation.
248
249 We start the drag operation using QDrag's \l{QDrag::}{exec()} function,
250 requesting that the magnet is copied when the drag is completed.
251
252 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 17
253
254 The function returns the drop action actually performed by the user
255 (this can be either a copy or a move action in this case); if this
256 action is equal to Qt::MoveAction we will close the activated
257 fridge magnet widget because we will create a new one to replace it
258 (see the \l{drop}{dropEvent()} implementation). Otherwise, if
259 the drop is outside our main widget, we simply show the widget in
260 its original position.
261
262 \section2 Dropping
263
264 When a a drag and drop action enters our widget, we will receive a
265 drag enter \e event. QDragEnterEvent inherits most of its
266 functionality from QDragMoveEvent, which in turn inherits most of
267 its functionality from QDropEvent. Note that we must accept this
268 event in order to receive the drag move events that are sent while
269 the drag and drop action is in progress. The drag enter event is
270 always immediately followed by a drag move event.
271
272 In our \c dragEnterEvent() implementation, we first determine
273 whether we support the event's MIME type or not:
274
275 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 4
276 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 5
277 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 6
278
279 If the type is \c application/x-fridgemagnet and the event
280 origins from any of this application's fridge magnet widgets, we
281 first set the event's drop action using the
282 QDropEvent::setDropAction() method. An event's drop action is the
283 action to be performed on the data by the target. Qt::MoveAction
284 indicates that the data is moved from the source to the target.
285
286 Then we call the event's \l {QDragMoveEvent::}{accept()} method to
287 indicate that we have handled the event. In general, unaccepted
288 events might be propagated to the parent widget. If the event
289 origins from any other widget, we simply accept the proposed
290 action.
291
292 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 7
293
294 We also accept the proposed action if the event's MIME type is \c
295 text/plain, i.e., if QMimeData::hasText() returns true. If the
296 event has any other type, on the other hand, we call the event's
297 \l {QDragMoveEvent::}{ignore()} method allowing the event to be
298 propagated further.
299
300 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 8
301
302 Drag move events occur when the cursor enters a widget, when it
303 moves within the widget, and when a modifier key is pressed on the
304 keyboard while the widget has focus. Our widget will receive drag
305 move events repeatedly while a drag is within its boundaries. We
306 reimplement the \l {QWidget::}{dragMoveEvent()} method, and
307 examine the event in the exact same way as we did with drag enter
308 events.
309
310 Note that the \l{QWidget::}{dropEvent()} event handler behaves
311 slightly differently: We first get hold of the event's MIME
312 data.
313
314 \target drop
315 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 9
316
317 The QMimeData class provides a container for data that
318 records information about its MIME type. QMimeData objects
319 associate the data that they hold with the corresponding MIME
320 types to ensure that information can be safely transferred between
321 applications, and copied around within the same application.
322
323 We retrieve the data associated with the \c application/x-fridgemagnet
324 MIME type using a data stream in order to create a new \c DragLabel
325 object.
326
327 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 10
328
329 The QDataStream class provides serialization of binary data to a
330 QIODevice (a data stream is a binary stream of encoded information
331 which is completely independent of the host computer's operating
332 system, CPU or byte order).
333
334 Finally, we create a label and move it to the event's position:
335
336 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 11
337
338 If the source of the event is also the widget receiving the
339 drop event, we set the event's drop action to Qt::MoveAction and
340 call the event's \l{QDragMoveEvent::}{accept()}
341 method. Otherwise, we simply accept the proposed action. This
342 means that labels are moved rather than copied in the same
343 window. However, if we drag a label to a second instance of the
344 Fridge Magnets example, the default action is to copy it, leaving
345 the original in the first instance.
346
347 If the event's MIME type is \c text/plain (i.e., if
348 QMimeData::hasText() returns true) we retrieve its text and split
349 it into words. For each word we create a new \c DragLabel action,
350 and show it at the event's position plus an offset depending on
351 the number of words in the text. In the end we accept the proposed
352 action. This lets the user drop selected text from a text editor or
353 Web browser onto the widget to add more fridge magnets.
354
355 \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 12
356
357 If the event has any other type, we call the event's
358 \l{QDragMoveEvent::}{ignore()} method allowing the event to be
359 propagated further.
360
361 \section1 Summary
362
363 We set our main widget's \l{QWidget::}{acceptDrops} property
364 and reimplemented QWidget's \l{QWidget::}{dragEnterEvent()},
365 \l{QWidget::}{dragMoveEvent()} and \l{QWidget::}{dropEvent()} event
366 handlers to support content dropped on our widget.
367
368 In addition, we reimplemented the \l{QWidget::}{mousePressEvent()}
369 function to let the user pick up fridge magnets in the first place.
370
371 Because data is communicated using drag and drop operations and
372 encoded using MIME types, you can run more than one instance of this
373 example, and transfer magnets between them.
374*/
Note: See TracBrowser for help on using the repository browser.