doc/src/examples/fridgemagnets.qdoc
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 */