diff -r 000000000000 -r 1918ee327afb doc/src/examples/fridgemagnets.qdoc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/src/examples/fridgemagnets.qdoc Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! + \example draganddrop/fridgemagnets + \title Fridge Magnets Example + + The Fridge Magnets example shows how to supply more than one type + of MIME-encoded data with a drag and drop operation. + + \image fridgemagnets-example.png + + With this application the user can play around with a collection + of fridge magnets, using drag and drop to form new sentences from + the words on the magnets. The example consists of two classes: + + \list + \o \c DragLabel is a custom widget representing one + single fridge magnet. + \o \c DragWidget provides the main application window. + \endlist + + We will first take a look at the \c DragLabel class, then we will + examine the \c DragWidget class. + + \section1 DragLabel Class Definition + + Each fridge magnet is represented by an instance of the \c + DragLabel class: + + \snippet examples/draganddrop/fridgemagnets/draglabel.h 0 + + Each instance of this QLabel subclass will be used to display an + pixmap generated from a text string. Since we cannot store both + text and a pixmap in a standard label, we declare a private variable + to hold the original text, and we define an additional member + function to allow it to be accessed. + + \section1 DragLabel Class Implementation + + In the \c DragLabel constructor, we first create a QImage object + on which we will draw the fridge magnet's text and frame: + + \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 0 + + Its size depends on the current font size, and its format is + QImage::Format_ARGB32_Premultiplied; i.e., the image is stored + using a premultiplied 32-bit ARGB format (0xAARRGGBB). + + We then construct a font object that uses the application's + default font, and set its style strategy. The style strategy tells + the font matching algorithm what type of fonts should be used to + find an appropriate default family. The QFont::ForceOutline forces + the use of outline fonts. + + To draw the text and frame onto the image, we use the QPainter + class. QPainter provides highly optimized methods to do most of + the drawing GUI programs require. It can draw everything from + simple lines to complex shapes like pies and chords. It can also + draw aligned text and pixmaps. + + \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 1 + + A painter can be activated by passing a paint device to the + constructor, or by using the \l{QPainter::}{begin()} method as we + do in this example. The \l{QPainter::}{end()} method deactivates + it. Note that the latter function is called automatically upon + destruction when the painter is actived by its constructor. The + QPainter::Antialiasing render hint ensures that the paint engine + will antialias the edges of primitives if possible. + + When the painting is done, we convert our image to a pixmap using + QPixmap's \l {QPixmap::}{fromImage()} method. This method also + takes an optional flags argument, and converts the given image to + a pixmap using the specified flags to control the conversion (the + flags argument is a bitwise-OR of the Qt::ImageConversionFlags; + passing 0 for flags sets all the default options). + + \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 2 + + Finally, we set the label's \l{QLabel::pixmap}{pixmap property} + and store the label's text for later use. + + \e{Note that setting the pixmap clears any previous content, including + any text previously set using QLabel::setText(), and disables + the label widget's buddy shortcut, if any.} + + \section1 DragWidget Class Definition + + The \c DragWidget class inherits QWidget, providing support for + drag and drop operations: + + \snippet examples/draganddrop/fridgemagnets/dragwidget.h 0 + + To make the widget responsive to drag and drop operations, we simply + reimplement the \l{QWidget::}{dragEnterEvent()}, + \l{QWidget::}{dragMoveEvent()} and \l{QWidget::}{dropEvent()} event + handlers inherited from QWidget. + + We also reimplement \l{QWidget::}{mousePressEvent()} to make the + widget responsive to mouse clicks. This is where we will write code + to start drag and drop operations. + + \section1 DragWidget Class Implementation + + In the constructor, we first open the file containing the words on + our fridge magnets: + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 0 + + QFile is an I/O device for reading and writing text and binary + files and resources, and may be used by itself or in combination + with QTextStream or QDataStream. We have chosen to read the + contents of the file using the QTextStream class that provides a + convenient interface for reading and writing text. + + We then create the fridge magnets. As long as there is data (the + QTextStream::atEnd() method returns true if there is no more data + to be read from the stream), we read one line at a time using + QTextStream's \l {QTextStream::}{readLine()} method. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 1 + + For each line, we create a \c DragLabel object using the read line + as text, we calculate its position and ensure that it is visible by + calling the QWidget::show() method. We set the Qt::WA_DeleteOnClose + attribute on each label to ensure that any unused labels will be + deleted; we will need to create new labels and delete old ones when + they are dragged around, and this ensures that the example does not + leak memory. + + We also set the \c FridgeMagnets widget's palette, minimum size + and window title. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 2 + + Finally, to enable our user to move the fridge magnets around, we + must also set the \c FridgeMagnets widget's + \l{QWidget::acceptDrops}{acceptDrops} property. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 3 + + Setting this property to true announces to the system that this + widget \e may be able to accept drop events (events that are sent + when drag and drop actions are completed). Later, we will + implement the functions that ensure that the widget accepts the + drop events it is interested in. + + \section2 Dragging + + Let's take a look at the \l{QWidget::}{mousePressEvent()} event + handler, where drag and drop operations begin: + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 13 + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 14 + + Mouse events occur when a mouse button is pressed or released + inside a widget, or when the mouse cursor is moved. By + reimplementing the \l{QWidget::}{mousePressEvent()} method we + ensure that we will receive mouse press events for the widget + containing the fridge magnets. + + Whenever we receive such an event, we first check to see if the + position of the click coincides with one of the labels. If not, + we simply return. + + If the user clicked a label, we determine the position of the + \e{hot spot} (the position of the click relative to the top-left + corner of the label). We create a byte array to store the label's + text and the hot spot, and we use a QDataStream object to stream + the data into the byte array. + + With all the information in place, we create a new QMimeData object. + As mentioned above, QMimeData objects associate the data that they + hold with the corresponding MIME types to ensure that information + can be safely transferred between applications. The + \l{QMimeData::}{setData()} method sets the data associated with a + given MIME type. In our case, we associate our item data with the + custom \c application/x-fridgemagnet type. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 15 + + Note that we also associate the magnet's text with the + \c text/plain MIME type using QMimeData's \l{QMimeData::}{setText()} + method. Below, we will see how our widget detects both these MIME + types with its event handlers. + + Finally, we create a QDrag object. It is the QDrag class that + handles most of the details of a drag and drop operation, + providing support for MIME-based drag and drop data transfer. The + data to be transferred by the drag and drop operation is contained + in a QMimeData object. When we call QDrag's + \l{QDrag::}{setMimeData()} method the ownership of our item data is + transferred to the QDrag object. + + We call the \l{QDrag::}{setPixmap()} function to set the pixmap used + to represent the data during the drag and drop operation. + Typically, this pixmap shows an icon that represents the MIME type + of the data being transferred, but any pixmap can be used. In this + example, we simply use the pixmap used by the label itself to make + it look like the fridge magnet itself is being moved. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 16 + + We also specify the cursor's hot spot, its position relative to the + top-level corner of the drag pixmap, to be the point we calculated + above. This makes the process of dragging the label feel more natural + because the cursor always points to the same place on the label + during the drag operation. + + We start the drag operation using QDrag's \l{QDrag::}{exec()} function, + requesting that the magnet is copied when the drag is completed. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 17 + + The function returns the drop action actually performed by the user + (this can be either a copy or a move action in this case); if this + action is equal to Qt::MoveAction we will close the activated + fridge magnet widget because we will create a new one to replace it + (see the \l{drop}{dropEvent()} implementation). Otherwise, if + the drop is outside our main widget, we simply show the widget in + its original position. + + \section2 Dropping + + When a a drag and drop action enters our widget, we will receive a + drag enter \e event. QDragEnterEvent inherits most of its + functionality from QDragMoveEvent, which in turn inherits most of + its functionality from QDropEvent. Note that we must accept this + event in order to receive the drag move events that are sent while + the drag and drop action is in progress. The drag enter event is + always immediately followed by a drag move event. + + In our \c dragEnterEvent() implementation, we first determine + whether we support the event's MIME type or not: + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 4 + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 5 + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 6 + + If the type is \c application/x-fridgemagnet and the event + origins from any of this application's fridge magnet widgets, we + first set the event's drop action using the + QDropEvent::setDropAction() method. An event's drop action is the + action to be performed on the data by the target. Qt::MoveAction + indicates that the data is moved from the source to the target. + + Then we call the event's \l {QDragMoveEvent::}{accept()} method to + indicate that we have handled the event. In general, unaccepted + events might be propagated to the parent widget. If the event + origins from any other widget, we simply accept the proposed + action. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 7 + + We also accept the proposed action if the event's MIME type is \c + text/plain, i.e., if QMimeData::hasText() returns true. If the + event has any other type, on the other hand, we call the event's + \l {QDragMoveEvent::}{ignore()} method allowing the event to be + propagated further. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 8 + + Drag move events occur when the cursor enters a widget, when it + moves within the widget, and when a modifier key is pressed on the + keyboard while the widget has focus. Our widget will receive drag + move events repeatedly while a drag is within its boundaries. We + reimplement the \l {QWidget::}{dragMoveEvent()} method, and + examine the event in the exact same way as we did with drag enter + events. + + Note that the \l{QWidget::}{dropEvent()} event handler behaves + slightly differently: We first get hold of the event's MIME + data. + + \target drop + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 9 + + The QMimeData class provides a container for data that + records information about its MIME type. QMimeData objects + associate the data that they hold with the corresponding MIME + types to ensure that information can be safely transferred between + applications, and copied around within the same application. + + We retrieve the data associated with the \c application/x-fridgemagnet + MIME type using a data stream in order to create a new \c DragLabel + object. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 10 + + The QDataStream class provides serialization of binary data to a + QIODevice (a data stream is a binary stream of encoded information + which is completely independent of the host computer's operating + system, CPU or byte order). + + Finally, we create a label and move it to the event's position: + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 11 + + If the source of the event is also the widget receiving the + drop event, we set the event's drop action to Qt::MoveAction and + call the event's \l{QDragMoveEvent::}{accept()} + method. Otherwise, we simply accept the proposed action. This + means that labels are moved rather than copied in the same + window. However, if we drag a label to a second instance of the + Fridge Magnets example, the default action is to copy it, leaving + the original in the first instance. + + If the event's MIME type is \c text/plain (i.e., if + QMimeData::hasText() returns true) we retrieve its text and split + it into words. For each word we create a new \c DragLabel action, + and show it at the event's position plus an offset depending on + the number of words in the text. In the end we accept the proposed + action. This lets the user drop selected text from a text editor or + Web browser onto the widget to add more fridge magnets. + + \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 12 + + If the event has any other type, we call the event's + \l{QDragMoveEvent::}{ignore()} method allowing the event to be + propagated further. + + \section1 Summary + + We set our main widget's \l{QWidget::}{acceptDrops} property + and reimplemented QWidget's \l{QWidget::}{dragEnterEvent()}, + \l{QWidget::}{dragMoveEvent()} and \l{QWidget::}{dropEvent()} event + handlers to support content dropped on our widget. + + In addition, we reimplemented the \l{QWidget::}{mousePressEvent()} + function to let the user pick up fridge magnets in the first place. + + Because data is communicated using drag and drop operations and + encoded using MIME types, you can run more than one instance of this + example, and transfer magnets between them. +*/