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

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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