Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

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

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/doc/src/examples/dragdroprobot.qdoc

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    77** This file is part of the documentation of the Qt Toolkit.
    88**
    9 ** $QT_BEGIN_LICENSE:LGPL$
     9** $QT_BEGIN_LICENSE:FDL$
    1010** Commercial Usage
    1111** Licensees holding valid Qt Commercial licenses may use this file in
    1212** 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.
     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.
    3521**
    3622** If you have questions regarding the use of this file, please contact
     
    4430    \title Drag and Drop Robot Example
    4531
    46     This GraphicsView example shows how to implement drag and drop in
    47     a QGraphicsItem subclass, as well as how to animate items using
    48     QGraphicsItemAnimation and QTimeLine.
     32    This GraphicsView example shows how to implement Drag and Drop in a
     33    QGraphicsItem subclass, as well as how to animate items using Qt's
     34    \l{Animation Framework}.
    4935
    5036    \image dragdroprobot-example.png
     37
     38    Graphics View provides the QGraphicsScene class for managing and
     39    interacting with a large number of custom-made 2D graphical items derived
     40    from the QGraphicsItem class, and a QGraphicsView widget for visualizing
     41    the items, with support for zooming and rotation.
     42
     43    This example consists of a \c Robot class, a \c ColorItem class, and a main
     44    function: the \c Robot class describes a simple robot consisting of several
     45    \c RobotPart derived limbs, including \c RobotHead and \c RobotLimb, the \c
     46    ColorItem class provides a draggable colored ellipse, and the \c main()
     47    function provides the main application window.
     48
     49    We will first review the \c Robot class to see how to assemble the
     50    different parts so that they can be individually rotated and animated using
     51    QPropertyAnimation, and we will then review the \c ColorItem class to
     52    demonstrate how to implement Drag and Drop between items. Finally we will
     53    review the main() function to see how we can put all the pieces together,
     54    to form the final application.
     55
     56    \section1 Robot Class Definition
     57
     58    The robot consists of three main classes: the \c RobotHead, the \c
     59    RobotTorso, and the \c RobotLimb, which is used for the upper and lower
     60    arms and legs. All parts derive from the \c RobotPart class, which in turn
     61    inherits \c QGraphicsObject. The \c Robot class itself has no visual
     62    appearance and serves only as a root node for the robot.
     63
     64    Let's start with the \c RobotPart class declaration.
     65
     66    \snippet examples/graphicsview/dragdroprobot/robot.h 0
     67
     68    This base class inherits QGraphicsObject. QGraphicsObject provides signals
     69    and slots through inheriting QObject, and it also declares QGraphicsItem's
     70    properties using Q_PROPERTY, which makes the properties accessible for
     71    QPropertyAnimation.
     72
     73    RobotPart also implements the three most important event handlers for
     74    accepting drop events:
     75    \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()},
     76    \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()}, and
     77    \l{QGraphicsItem::dropEvent()}{dropEvent()}.
     78
     79    The color is stored as a member variable, along with the \c dragOver
     80    variable, which we will use later to indicate visually that the limb can
     81    accept colors that are is dragged onto it.
     82
     83    \snippet examples/graphicsview/dragdroprobot/robot.cpp 0
     84
     85    \c RobotPart's constructor initializes the dragOver member and sets the
     86    color to Qt::lightGray. In the constructor body we enable support for
     87    accepting drop events by calling
     88    \l{QGraphicsItem::setAcceptDrops()}{setAcceptDrops(true)}.
     89
     90    The rest of this class's implementation is to support Drag and Drop.
     91
     92    \snippet examples/graphicsview/dragdroprobot/robot.cpp 1
     93
     94    The \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} handler is called
     95    when a Drag and Drop element is dragged into the robot part's area.
     96
     97    The handler implementation determines whether or not this item as a whole
     98    can accept the mime data assiciated with the incoming drag object. \c
     99    RobotPart provides a base behavior for all parts that accepts color drops.
     100    So if the incoming drag object contains a color, the event is accepted, we
     101    set \c dragOver to \c true and call update() to help provide positive
     102    visual feedback to the user; otherwise the event is ignored, which in turn
     103    allows the event to propagate to parent elements.
     104
     105    \snippet examples/graphicsview/dragdroprobot/robot.cpp 2
     106
     107    The \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()} handler is called
     108    when a Drag and Drop element is dragged away from the robot part's area.
     109    Our implementation simply resets \e dragOver to false and calls
     110    \l{QGraphicsItem::update()}{update()} to help provide visual feedback that
     111    the drag has left this item.
     112
     113    \snippet examples/graphicsview/dragdroprobot/robot.cpp 3
     114
     115    The \l{QGraphicsItem::dropEvent()}{dropEvent()} handler is called when a
     116    Drag and Drop element is dropped onto an item (i.e., when the mouse button
     117    is released over the item while dragging).
     118
     119    We reset \c dragOver to false, assign the item's new color, and call
     120    \l{QGraphicsItem::update()}{update()}.
     121
     122    The declaration and implementation of \c RobotHead, \c RobotTorso, and \c
     123    RobotLimb are practically identical. We will review \c RobotHead in detail,
     124    as this class has one minor difference, and leave the other classes as an
     125    exercise for the reader.
     126
     127    \snippet examples/graphicsview/dragdroprobot/robot.h 1
     128
     129    The \c RobotHead class inherits \c RobotPart and provides the necessary
     130    implementations of \l{QGraphicsItem::boundingRect()}{boundingRect()} and
     131    \l{QGraphicsItem::paint()}{paint()}. It also reimplements
     132    \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} and dropEvent() to
     133    provide special handling of image drops.
     134
     135    The class contains a private pixmap member that we can use to implement
     136    support for accepting image drops.
     137
     138    \snippet examples/graphicsview/dragdroprobot/robot.cpp 4
     139
     140    \c RobotHead has a rather plain constructor that simply forwards to
     141    \c RobotPart's constructor.
     142
     143    \snippet examples/graphicsview/dragdroprobot/robot.cpp 5
     144
     145    The \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation
     146    returns the extents for the head. Because we want the center of rotation to
     147    be the bottom center of the item, we have chosen a bounding rectangle that
     148    starts at (-15, -50) and extends to 30 units wide and 50 units tall. When
     149    rotating the head, the "neck" will stay still while the top of the head
     150    tilts from side to side.
     151
     152    \snippet examples/graphicsview/dragdroprobot/robot.cpp 6
     153
     154    In \l{QGraphicsItem::paint()}{paint()} we draw the actual head. The
     155    implementation is split into two sections; if an image has been dropped
     156    onto the head, we draw the image, otherwise we draw a round rectangular
     157    robot head with simple vector graphics.
     158
     159    For performance reasons, depending on the complexity of what is painted, it
     160    can often be faster to draw the head as an image rather than using a
     161    sequence of vector operations.
     162
     163    \snippet examples/graphicsview/dragdroprobot/robot.cpp 7
     164
     165    The robot head can accept image drops. In order to support this, its
     166    reimplementation of \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()}
     167    checks if the drag object contains image data, and if it does, then the
     168    event is accepted. Otherwise we fall back to the base \c RobotPart
     169    implementation.
     170
     171    \snippet examples/graphicsview/dragdroprobot/robot.cpp 8
     172
     173    To follow up on image support, we must also implement
     174    \l{QGraphicsItem::dropEvent()}{dropEvent()}. We check if the drag object
     175    contains image data, and if it does, we store this data as a member pixmap
     176    and call \l{QGraphicsItem::update()}{update()}. This pixmap is used inside
     177    the \l{QGraphicsItem::paint()}{paint()} implementation that we reviewed
     178    before.
     179
     180    \c RobotTorso and \c RobotLimb are similar to \c RobotHead, so let's
     181    skip directly to the \c Robot class.
     182
     183    \snippet examples/graphicsview/dragdroprobot/robot.h 4
     184
     185    The \c Robot class also inherits \c RobotPart, and like the other parts it
     186    also implements \l{QGraphicsItem::boundingRect()}{boundingRect()} and
     187    \l{QGraphicsItem::paint()}{paint()}. It provides a rather special
     188    implementation, though:
     189
     190    \snippet examples/graphicsview/dragdroprobot/robot.cpp 9
     191
     192    Because the \c Robot class is only used as a base node for the rest of the
     193    robot, it has no visual representation. Its
     194    \l{QGraphicsItem::boundingRect()}{boundingRect()} implementation can
     195    therefore return a null QRectF, and its paint() function does nothing.
     196
     197    \snippet examples/graphicsview/dragdroprobot/robot.cpp 10
     198
     199    The constuctor starts by setting the flag
     200    \l{QGraphicsItem::ItemHasNoContents}{ItemHasNoContents}, which is a minor
     201    optimization for items that have no visual appearance.
     202
     203    We then construct all the robot parts (head, torso, and upper/lower arms
     204    and legs). The stacking order is very important, and we use the
     205    parent-child hierarchy to ensure the elements rotate and move properly. We
     206    construct the torso first, as this is the root element. We then construct
     207    the head and pass the torso to \c HeadItem's constructor. This will make
     208    the head a child of the torso; if you rotate the torso, the head will
     209    follow. The same pattern is applied to the rest of the limbs.
     210
     211    \snippet examples/graphicsview/dragdroprobot/robot.cpp 11
     212
     213    Each robot part is carefully positioned. For example, the upper left arm is
     214    moved precisely to the top-left area of the torso, and the upper right arm
     215    is moved to the top-right area.
     216
     217    \snippet examples/graphicsview/dragdroprobot/robot.cpp 12
     218
     219    The next section creates all animation objects. This snippet shows the two
     220    animations that operate on the head's scale and rotation. The two
     221    QPropertyAnimation instances simply set the object, property, and
     222    respective start and end values.
     223
     224    All animations are controlled by one top-level parallel animation group.
     225    The scale and rotation animations are added to this group.
     226
     227    The rest of the animations are defined in a similar way.
     228
     229    \snippet examples/graphicsview/dragdroprobot/robot.cpp 13
     230
     231    Finally we set an easing curve and duration on each animation, ensure the
     232    toplevel animation group loops forever, and start the toplevel animation.
     233
     234    \section1 ColorItem Class Definition
     235
     236    The \c ColorItem class represents a circular item that can be pressed to
     237    drag colors onto robot parts.
     238
     239    \snippet examples/graphicsview/dragdroprobot/coloritem.h 0
     240
     241    This class is very simple. It does not use animations, and has no need for
     242    properties nor signals and slots, so to save resources, it's most natural
     243    that it inherits QGraphicsItem (as opposed to QGraphicsObject).
     244
     245    It declares the mandatory \l{QGraphicsItem::boundingRect()}{boundingRect()}
     246    and \l{QGraphicsItem::paint()}{paint()} functions, and adds
     247    reimplementations of
     248    \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()},
     249    \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()}, and
     250    \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()}. It contains a
     251    single private color member.
     252
     253    Let's take a look at its implementation.
     254
     255    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 0
     256
     257    \c ColorItem's constructor assigns an opaque random color to its color
     258    member by making use of qrand(). For improved usability, it assigns a
     259    tooltip that provides a useful hint to the user, and it also sets a
     260    suitable cursor. This ensures that the cursor will chance to
     261    Qt::OpenHandCursor when the mouse pointer hovers over the item.
     262
     263    Finally, we call
     264    \l{QGraphicsItem::setAcceptedMouseButtons()}{setAcceptedMouseButtons()} to
     265    ensure that this item can only process Qt::LeftButton. This simplifies the
     266    mouse event handlers greatly, as we can always assume that only the left
     267    mouse button is pressed and released.
     268
     269    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 1
     270
     271    The item's bounding rect is a fixed 30x30 units centered around the item's
     272    origin (0, 0), and adjusted by 0.5 units in all directions to allow a
     273    scalable pen to draw its outline. For a final visual touch the bounds
     274    also compensate with a few units down and to the right to make room
     275    for a simple dropshadow.
     276
     277    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 2
     278
     279    The \l{QGraphicsItem::paint()}{paint()} implementation draws an ellipse
     280    with a 1-unit black outline, a plain color fill, and a dark gray
     281    dropshadow.
     282
     283    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 3
     284
     285    The \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()} handler is
     286    called when you press the mouse button inside the item's area. Our
     287    implementation simply sets the cursor to Qt::ClosedHandCursor.
     288
     289    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 4
     290
     291    The \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()} handler is
     292    called when you release the mouse button after having pressed it inside an
     293    item's area. Our implementation sets the cursor back to Qt::OpenHandCursor.
     294    The mouse press and release event handlers together provide useful visual
     295    feedback to the user: when you move the mouse pointer over a \c CircleItem,
     296    the cursor changes to an open hand. Pressing the item will show a closed
     297    hand cursor. Releasing will restore to an open hand cursor again.
     298
     299    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 5
     300
     301    The \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()} handler is called
     302    when you move the mouse around after pressing the mouse button inside the
     303    \c ColorItem's area. This implementation provides the most important piece
     304    of logic for \c CircleItem: the code that starts and manages drags.
     305
     306    The implementation starts by checking if the mouse has been dragged far
     307    enough to eliminate mouse jitter noise. We only want to start a drag if the
     308    mouse has been dragged farther than the application start drag distance.
     309
     310    Continuing, we create a QDrag object, passing the event
     311    \l{QGraphicsSceneEvent::widget()}{widget} (i.e., the QGraphicsView
     312    viewport) to its constructor. Qt will ensure that this object is deleted at
     313    the right time. We also create a QMimeData instance that can contain our
     314    color or image data, and assign this to the drag object.
     315
     316    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 6
     317
     318    This snippet has a somewhat random outcome: once in a while, a special
     319    image is assigned to the drag object's mime data. The pixmap is also
     320    assiged as the drag object's pixmap. This will ensure that you can see the
     321    image that is being dragged as a pixmap under the mouse cursor.
     322
     323    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 7
     324
     325    Otherwise, and this is the most common outcome, a simple color is assigned
     326    to the drag object's mime data. We render this \c ColorItem into a new
     327    pixmap to give the user visual feedback that the color is being "dragged".
     328
     329    \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 8
     330
     331    Finally we execute the drag. QDrag::exec() will reenter the event loop, and
     332    only exit if the drag has either been dropped, or canceled. In any case we
     333    reset the cursor to Qt::OpenHandCursor.
     334
     335    \section1 The main() Function
     336
     337    Now that the \c Robot and \c ColorItem classes are complete, we can put all
     338    the pieces together inside the main() function.
     339
     340    \snippet examples/graphicsview/dragdroprobot/main.cpp 0
     341
     342    We start off by constructing QApplication, and initializing the random
     343    number generator. This ensures that the color items have different colors
     344    every time the application starts.
     345
     346    \snippet examples/graphicsview/dragdroprobot/main.cpp 1
     347
     348    We construct a fixed size scene, and create 10 \c ColorItem instances
     349    arranged in a circle. Each item is added to the scene.
     350
     351    In the center of this circle we create one \c Robot instance. The
     352    robot is scaled and moved up a few units. It is then added to the scene.
     353
     354    \snippet examples/graphicsview/dragdroprobot/main.cpp 2
     355
     356    Finally we create a QGraphicsView window, and assign the scene to it.
     357
     358    For increased visual quality, we enable antialiasing. We also choose to use
     359    bounding rectangle updates to simplify visual update handling.
     360    The view is given a fixed sand-colored background, and a window title.
     361
     362    We then show the view. The animations start immediately after
     363    control enters the event loop.
    51364*/
     365
Note: See TracChangeset for help on using the changeset viewer.