diff options
-rw-r--r-- | doc/src/examples/dragdroprobot.qdoc | 334 | ||||
-rw-r--r-- | doc/src/getting-started/examples.qdoc | 2 | ||||
-rw-r--r-- | examples/graphicsview/dragdroprobot/coloritem.cpp | 24 | ||||
-rw-r--r-- | examples/graphicsview/dragdroprobot/coloritem.h | 2 | ||||
-rw-r--r-- | examples/graphicsview/dragdroprobot/main.cpp | 8 | ||||
-rw-r--r-- | examples/graphicsview/dragdroprobot/robot.cpp | 217 | ||||
-rw-r--r-- | examples/graphicsview/dragdroprobot/robot.h | 29 |
7 files changed, 504 insertions, 112 deletions
diff --git a/doc/src/examples/dragdroprobot.qdoc b/doc/src/examples/dragdroprobot.qdoc index 413f190..887b254 100644 --- a/doc/src/examples/dragdroprobot.qdoc +++ b/doc/src/examples/dragdroprobot.qdoc @@ -43,9 +43,337 @@ \example graphicsview/dragdroprobot \title Drag and Drop Robot Example - This GraphicsView example shows how to implement drag and drop in - a QGraphicsItem subclass, as well as how to animate items using - QGraphicsItemAnimation and QTimeLine. + This GraphicsView example shows how to implement Drag and Drop in a + QGraphicsItem subclass, as well as how to animate items using Qt's + \l{Animation Framework}. \image dragdroprobot-example.png + + Graphics View provides the QGraphicsScene class for managing and + interacting with a large number of custom-made 2D graphical items derived + from the QGraphicsItem class, and a QGraphicsView widget for visualizing + the items, with support for zooming and rotation. + + This example consists of a \c Robot class, a \c ColorItem class, and a main + function: the \c Robot class describes a simple robot consisting of several + \c RobotPart derived limbs, including \c RobotHead and \c RobotLimb, the \c + ColorItem class provides a draggable colored ellipse, and the \c main() + function provides the main application window. + + We will first review the \c Robot class to see how to assemble the + different parts so that they can be individually rotated and animated using + QPropertyAnimation, and we will then review the \c ColorItem class to + demonstrate how to implement Drag and Drop between items. Finally we will + review the main() function to see how we can put all the pieces together, + to form the final application. + + \section1 Robot Class Definition + + The robot consists of three main classes: the \c RobotHead, the \c + RobotTorso, and the \c RobotLimb, which is used for the upper and lower + arms and legs. All parts derive from the \c RobotPart class, which in turn + inherits \c QGraphicsObject. The \c Robot class itself has no visual + appearance and serves only as a root node for the robot. + + Let's start with the \c RobotPart class declaration. + + \snippet examples/graphicsview/dragdroprobot/robot.h 0 + + This base class inherits QGraphicsObject. QGraphicsObject provides signals + and slots through inheriting QObject, and it also declares QGraphicsItem's + properties using Q_PROPERTY, which makes the properties accessible for + QPropertyAnimation. + + RobotPart also implements the three most important event handlers for + accepting drop events: + \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()}, + \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()}, and + \l{QGraphicsItem::dropEvent()}{dropEvent()}. + + The color is stored as a member variable, along with the \c dragOver + variable, which we will use later to indicate visually that the limb can + accept colors that are is dragged onto it. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 0 + + \c RobotPart's constructor initializes the dragOver member and sets the + color to Qt::lightGray. In the constructor body we enable support for + accepting drop events by calling + \l{QGraphicsItem::setAcceptDrops()}{setAcceptDrops(true)}. + + The rest of this class's implementation is to support Drag and Drop. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 1 + + The \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} handler is called + when a Drag and Drop element is dragged into the robot part's area. + + The handler implementation determines whether or not this item as a whole + can accept the mime data assiciated with the incoming drag object. \c + RobotPart provides a base behavior for all parts that accepts color drops. + So if the incoming drag object contains a color, the event is accepted, we + set \c dragOver to \c true and call update() to help provide positive + visual feedback to the user; otherwise the event is ignored, which in turn + allows the event to propagate to parent elements. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 2 + + The \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()} handler is called + when a Drag and Drop element is dragged away from the robot part's area. + Our implementation simply resets \e dragOver to false and calls + \l{QGraphicsItem::update()}{update()} to help provide visual feedback that + the drag has left this item. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 3 + + The \l{QGraphicsItem::dropEvent()}{dropEvent()} handler is called when a + Drag and Drop element is dropped onto an item (i.e., when the mouse button + is released over the item while dragging). + + We reset \c dragOver to false, assign the item's new color, and call + \l{QGraphicsItem::update()}{update()}. + + The declaration and implementation of \c RobotHead, \c RobotTorso, and \c + RobotLimb are practically identical. We will review \c RobotHead in detail, + as this class has one minor difference, and leave the other classes as an + exercise for the reader. + + \snippet examples/graphicsview/dragdroprobot/robot.h 1 + + The \c RobotHead class inherits \c RobotPart and provides the necessary + implementations of \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()}. It also reimplements + \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} and dropEvent() to + provide special handling of image drops. + + The class contains a private pixmap member that we can use to implement + support for accepting image drops. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 4 + + \c RobotHead has a rather plain constructor that simply forwards to + \c RobotPart's constructor. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 5 + + The \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation + returns the extents for the head. Because we want the center of rotation to + be the bottom center of the item, we have chosen a bounding rectangle that + starts at (-15, -50) and extends to 30 units wide and 50 units tall. When + rotating the head, the "neck" will stay still while the top of the head + tilts from side to side. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 6 + + In \l{QGraphicsItem::paint()}{paint()} we draw the actual head. The + implementation is split into two sections; if an image has been dropped + onto the head, we draw the image, otherwise we draw a round rectangular + robot head with simple vector graphics. + + For performance reasons, depending on the complexity of what is painted, it + can often be faster to draw the head as an image rather than using a + sequence of vector operations. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 7 + + The robot head can accept image drops. In order to support this, its + reimplementation of \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} + checks if the drag object contains image data, and if it does, then the + event is accepted. Otherwise we fall back to the base \c RobotPart + implementation. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 8 + + To follow up on image support, we must also implement + \l{QGraphicsItem::dropEvent()}{dropEvent()}. We check if the drag object + contains image data, and if it does, we store this data as a member pixmap + and call \l{QGraphicsItem::update()}{update()}. This pixmap is used inside + the \l{QGraphicsItem::paint()}{paint()} implementation that we reviewed + before. + + \c RobotTorso and \c RobotLimb are similar to \c RobotHead, so let's + skip directly to the \c Robot class. + + \snippet examples/graphicsview/dragdroprobot/robot.h 4 + + The \c Robot class also inherits \c RobotPart, and like the other parts it + also implements \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()}. It provides a rather special + implementation, though: + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 9 + + Because the \c Robot class is only used as a base node for the rest of the + robot, it has no visual representation. Its + \l{QGraphicsItem::boundingRect()}{boundingRect()} implementation can + therefore return a null QRectF, and its paint() function does nothing. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 10 + + The constuctor starts by setting the flag + \l{QGraphicsItem::ItemHasNoContents}{ItemHasNoContents}, which is a minor + optimization for items that have no visual appearance. + + We then construct all the robot parts (head, torso, and upper/lower arms + and legs). The stacking order is very important, and we use the + parent-child hierarchy to ensure the elements rotate and move properly. We + construct the torso first, as this is the root element. We then construct + the head and pass the torso to \c HeadItem's constructor. This will make + the head a child of the torso; if you rotate the torso, the head will + follow. The same pattern is applied to the rest of the limbs. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 11 + + Each robot part is carefully positioned. For example, the upper left arm is + moved precisely to the top-left area of the torso, and the upper right arm + is moved to the top-right area. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 12 + + The next section creates all animation objects. This snippet shows the two + animations that operate on the head's scale and rotation. The two + QPropertyAnimation instances simply set the object, property, and + respective start and end values. + + All animations are controlled by one top-level parallel animation group. + The scale and rotation animations are added to this group. + + The rest of the animations are defined in a similar way. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 13 + + Finally we set an easing curve and duration on each animation, ensure the + toplevel animation group loops forever, and start the toplevel animation. + + \section1 ColorItem Class Definition + + The \c ColorItem class represents a circular item that can be pressed to + drag colors onto robot parts. + + \snippet examples/graphicsview/dragdroprobot/coloritem.h 0 + + This class is very simple. It does not use animations, and has no need for + properties nor signals and slots, so to save resources, it's most natural + that it inherits QGraphicsItem (as opposed to QGraphicsObject). + + It declares the mandatory \l{QGraphicsItem::boundingRect()}{boundingRect()} + and \l{QGraphicsItem::paint()}{paint()} functions, and adds + reimplementations of + \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()}, + \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()}, and + \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()}. It contains a + single private color member. + + Let's take a look at its implementation. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 0 + + \c ColorItem's constructor assigns an opaque random color to its color + member by making use of qrand(). For improved usability, it assigns a + tooltip that provides a useful hint to the user, and it also sets a + suitable cursor. This ensures that the cursor will chance to + Qt::OpenHandCursor when the mouse pointer hovers over the item. + + Finally, we call + \l{QGraphicsItem::setAcceptedMouseButtons()}{setAcceptedMouseButtons()} to + ensure that this item can only process Qt::LeftButton. This simplifies the + mouse event handlers greatly, as we can always assume that only the left + mouse button is pressed and released. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 1 + + The item's bounding rect is a fixed 30x30 units centered around the item's + origin (0, 0), and adjusted by 0.5 units in all directions to allow a + scalable pen to draw its outline. For a final visual touch the bounds + also compensate with a few units down and to the right to make room + for a simple dropshadow. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 2 + + The \l{QGraphicsItem::paint()}{paint()} implementation draws an ellipse + with a 1-unit black outline, a plain color fill, and a dark gray + dropshadow. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 3 + + The \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()} handler is + called when you press the mouse button inside the item's area. Our + implementation simply sets the cursor to Qt::ClosedHandCursor. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 4 + + The \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()} handler is + called when you release the mouse button after having pressed it inside an + item's area. Our implementation sets the cursor back to Qt::OpenHandCursor. + The mouse press and release event handlers together provide useful visual + feedback to the user: when you move the mouse pointer over a \c CircleItem, + the cursor changes to an open hand. Pressing the item will show a closed + hand cursor. Releasing will restore to an open hand cursor again. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 5 + + The \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()} handler is called + when you move the mouse around after pressing the mouse button inside the + \c ColorItem's area. This implementation provides the most important piece + of logic for \c CircleItem: the code that starts and manages drags. + + The implementation starts by checking if the mouse has been dragged far + enough to eliminate mouse jitter noise. We only want to start a drag if the + mouse has been dragged farther than the application start drag distance. + + Continuing, we create a QDrag object, passing the event + \l{QGraphicsSceneEvent::widget()}{widget} (i.e., the QGraphicsView + viewport) to its constructor. Qt will ensure that this object is deleted at + the right time. We also create a QMimeData instance that can contain our + color or image data, and assign this to the drag object. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 6 + + This snippet has a somewhat random outcome: once in a while, a special + image is assigned to the drag object's mime data. The pixmap is also + assiged as the drag object's pixmap. This will ensure that you can see the + image that is being dragged as a pixmap under the mouse cursor. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 7 + + Otherwise, and this is the most common outcome, a simple color is assigned + to the drag object's mime data. We render this \c ColorItem into a new + pixmap to give the user visual feedback that the color is being "dragged". + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 8 + + Finally we execute the drag. QDrag::exec() will reenter the event loop, and + only exit if the drag has either been dropped, or canceled. In any case we + reset the cursor to Qt::OpenHandCursor. + + \section1 The main() Function + + Now that the \c Robot and \c ColorItem classes are complete, we can put all + the pieces together inside the main() function. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 0 + + We start off by constructing QApplication, and initializing the random + number generator. This ensures that the color items have different colors + every time the application starts. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 1 + + We construct a fixed size scene, and create 10 \c ColorItem instances + arranged in a circle. Each item is added to the scene. + + In the center of this circle we create one \c Robot instance. The + robot is scaled and moved up a few units. It is then added to the scene. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 2 + + Finally we create a QGraphicsView window, and assign the scene to it. + + For increased visual quality, we enable antialiasing. We also choose to use + bounding rectangle updates to simplify visual update handling. + The view is given a fixed sand-colored background, and a window title. + + We then show the view. The animations start immediately after + control enters the event loop. */ + diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 071a107..c96c70f 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -649,7 +649,7 @@ \list \o \l{graphicsview/collidingmice}{Colliding Mice}\raisedaster \o \l{graphicsview/diagramscene}{Diagram Scene}\raisedaster - \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot} + \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot}\raisedaster \o \l{graphicsview/elasticnodes}{Elastic Nodes} \o \l{graphicsview/portedasteroids}{Ported Asteroids} \o \l{graphicsview/portedcanvas}{Ported Canvas} diff --git a/examples/graphicsview/dragdroprobot/coloritem.cpp b/examples/graphicsview/dragdroprobot/coloritem.cpp index 95878b1..08edd38 100644 --- a/examples/graphicsview/dragdroprobot/coloritem.cpp +++ b/examples/graphicsview/dragdroprobot/coloritem.cpp @@ -43,6 +43,7 @@ #include "coloritem.h" +//! [0] ColorItem::ColorItem() : color(qrand() % 256, qrand() % 256, qrand() % 256) { @@ -50,13 +51,18 @@ ColorItem::ColorItem() .arg(color.red()).arg(color.green()).arg(color.blue()) .arg("Click and drag this color onto the robot!")); setCursor(Qt::OpenHandCursor); + setAcceptedMouseButtons(Qt::LeftButton); } +//! [0] +//! [1] QRectF ColorItem::boundingRect() const { return QRectF(-15.5, -15.5, 34, 34); } +//! [1] +//! [2] void ColorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); @@ -68,17 +74,16 @@ void ColorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, painter->setBrush(QBrush(color)); painter->drawEllipse(-15, -15, 30, 30); } +//! [2] +//! [3] void ColorItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() != Qt::LeftButton) { - event->ignore(); - return; - } - setCursor(Qt::ClosedHandCursor); } +//! [3] +//! [5] void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton)) @@ -89,7 +94,9 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QDrag *drag = new QDrag(event->widget()); QMimeData *mime = new QMimeData; drag->setMimeData(mime); +//! [5] +//! [6] static int n = 0; if (n++ > 2 && (qrand() % 3) == 0) { QImage image(":/images/head.png"); @@ -97,6 +104,8 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) drag->setPixmap(QPixmap::fromImage(image).scaled(30, 40)); drag->setHotSpot(QPoint(15, 30)); +//! [6] +//! [7] } else { mime->setColorData(color); mime->setText(QString("#%1%2%3") @@ -118,12 +127,17 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) drag->setPixmap(pixmap); drag->setHotSpot(QPoint(15, 20)); } +//! [7] +//! [8] drag->exec(); setCursor(Qt::OpenHandCursor); } +//! [8] +//! [4] void ColorItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) { setCursor(Qt::OpenHandCursor); } +//! [4] diff --git a/examples/graphicsview/dragdroprobot/coloritem.h b/examples/graphicsview/dragdroprobot/coloritem.h index 788d19e..eb19db6 100644 --- a/examples/graphicsview/dragdroprobot/coloritem.h +++ b/examples/graphicsview/dragdroprobot/coloritem.h @@ -44,6 +44,7 @@ #include <QGraphicsItem> +//! [0] class ColorItem : public QGraphicsItem { public: @@ -60,5 +61,6 @@ protected: private: QColor color; }; +//! [0] #endif diff --git a/examples/graphicsview/dragdroprobot/main.cpp b/examples/graphicsview/dragdroprobot/main.cpp index 02585e1..2669c41 100644 --- a/examples/graphicsview/dragdroprobot/main.cpp +++ b/examples/graphicsview/dragdroprobot/main.cpp @@ -46,12 +46,14 @@ #include <math.h> +//! [0] int main(int argc, char **argv) { QApplication app(argc, argv); qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); - +//! [0] +//! [1] QGraphicsScene scene(-200, -200, 400, 400); for (int i = 0; i < 10; ++i) { @@ -66,7 +68,8 @@ int main(int argc, char **argv) robot->scale(1.2, 1.2); robot->setPos(0, -20); scene.addItem(robot); - +//! [1] +//! [2] QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); @@ -76,3 +79,4 @@ int main(int argc, char **argv) return app.exec(); } +//! [2] diff --git a/examples/graphicsview/dragdroprobot/robot.cpp b/examples/graphicsview/dragdroprobot/robot.cpp index 9ac6d26..705bd9d 100644 --- a/examples/graphicsview/dragdroprobot/robot.cpp +++ b/examples/graphicsview/dragdroprobot/robot.cpp @@ -43,16 +43,18 @@ #include "robot.h" +//! [0] RobotPart::RobotPart(QGraphicsItem *parent) - : QGraphicsItem(parent), color(Qt::lightGray), dragOver(false) + : QGraphicsObject(parent), color(Qt::lightGray), dragOver(false) { setAcceptDrops(true); } +//! [0] +//! [1] void RobotPart::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { - if (event->mimeData()->hasColor() - || (qgraphicsitem_cast<RobotHead *>(this) && event->mimeData()->hasImage())) { + if (event->mimeData()->hasColor()) { event->setAccepted(true); dragOver = true; update(); @@ -60,34 +62,42 @@ void RobotPart::dragEnterEvent(QGraphicsSceneDragDropEvent *event) event->setAccepted(false); } } +//! [1] +//! [2] void RobotPart::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) { Q_UNUSED(event); dragOver = false; update(); } +//! [2] +//! [3] void RobotPart::dropEvent(QGraphicsSceneDragDropEvent *event) { dragOver = false; if (event->mimeData()->hasColor()) color = qVariantValue<QColor>(event->mimeData()->colorData()); - else if (event->mimeData()->hasImage()) - pixmap = qVariantValue<QPixmap>(event->mimeData()->imageData()); update(); } +//! [3] +//! [4] RobotHead::RobotHead(QGraphicsItem *parent) : RobotPart(parent) { } +//! [4] +//! [5] QRectF RobotHead::boundingRect() const { return QRectF(-15, -50, 30, 50); } +//! [5] +//! [6] void RobotHead::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { @@ -110,11 +120,33 @@ void RobotHead::paint(QPainter *painter, painter->drawPixmap(QPointF(-15 * 4.4, -50 * 3.54), pixmap); } } +//! [6] -int RobotHead::type() const +//! [7] +void RobotHead::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { - return Type; + if (event->mimeData()->hasImage()) { + event->setAccepted(true); + dragOver = true; + update(); + } else { + RobotPart::dragEnterEvent(event); + } } +//! [7] + +//! [8] +void RobotHead::dropEvent(QGraphicsSceneDragDropEvent *event) +{ + if (event->mimeData()->hasImage()) { + dragOver = false; + pixmap = qVariantValue<QPixmap>(event->mimeData()->imageData()); + update(); + } else { + RobotPart::dropEvent(event); + } +} +//! [8] RobotTorso::RobotTorso(QGraphicsItem *parent) : RobotPart(parent) @@ -161,19 +193,25 @@ void RobotLimb::paint(QPainter *painter, painter->drawEllipse(-5, -5, 10, 10); } -Robot::Robot() +//! [10] +Robot::Robot(QGraphicsItem *parent) + : RobotPart(parent) { - QGraphicsItem *torsoItem = new RobotTorso(this); - QGraphicsItem *headItem = new RobotHead(torsoItem); - QGraphicsItem *upperLeftArmItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerLeftArmItem = new RobotLimb(upperLeftArmItem); - QGraphicsItem *upperRightArmItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerRightArmItem = new RobotLimb(upperRightArmItem); - QGraphicsItem *upperRightLegItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerRightLegItem = new RobotLimb(upperRightLegItem); - QGraphicsItem *upperLeftLegItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerLeftLegItem = new RobotLimb(upperLeftLegItem); - + setFlag(ItemHasNoContents); + + QGraphicsObject *torsoItem = new RobotTorso(this); + QGraphicsObject *headItem = new RobotHead(torsoItem); + QGraphicsObject *upperLeftArmItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerLeftArmItem = new RobotLimb(upperLeftArmItem); + QGraphicsObject *upperRightArmItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerRightArmItem = new RobotLimb(upperRightArmItem); + QGraphicsObject *upperRightLegItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerRightLegItem = new RobotLimb(upperRightLegItem); + QGraphicsObject *upperLeftLegItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerLeftLegItem = new RobotLimb(upperLeftLegItem); +//! [10] + +//! [11] headItem->setPos(0, -18); upperLeftArmItem->setPos(-15, -10); lowerLeftArmItem->setPos(30, 0); @@ -183,82 +221,78 @@ Robot::Robot() lowerRightLegItem->setPos(30, 0); upperLeftLegItem->setPos(-10, 32); lowerLeftLegItem->setPos(30, 0); +//! [11] - timeLine = new QTimeLine; - - QGraphicsItemAnimation *headAnimation = new QGraphicsItemAnimation; - headAnimation->setItem(headItem); - headAnimation->setTimeLine(timeLine); - headAnimation->setRotationAt(0, 20); - headAnimation->setRotationAt(1, -20); - headAnimation->setScaleAt(1, 1.1, 1.1); - - QGraphicsItemAnimation *upperLeftArmAnimation = new QGraphicsItemAnimation; - upperLeftArmAnimation->setItem(upperLeftArmItem); - upperLeftArmAnimation->setTimeLine(timeLine); - upperLeftArmAnimation->setRotationAt(0, 190); - upperLeftArmAnimation->setRotationAt(1, 180); - - QGraphicsItemAnimation *lowerLeftArmAnimation = new QGraphicsItemAnimation; - lowerLeftArmAnimation->setItem(lowerLeftArmItem); - lowerLeftArmAnimation->setTimeLine(timeLine); - lowerLeftArmAnimation->setRotationAt(0, 50); - lowerLeftArmAnimation->setRotationAt(1, 10); - - QGraphicsItemAnimation *upperRightArmAnimation = new QGraphicsItemAnimation; - upperRightArmAnimation->setItem(upperRightArmItem); - upperRightArmAnimation->setTimeLine(timeLine); - upperRightArmAnimation->setRotationAt(0, 300); - upperRightArmAnimation->setRotationAt(1, 310); - - QGraphicsItemAnimation *lowerRightArmAnimation = new QGraphicsItemAnimation; - lowerRightArmAnimation->setItem(lowerRightArmItem); - lowerRightArmAnimation->setTimeLine(timeLine); - lowerRightArmAnimation->setRotationAt(0, 0); - lowerRightArmAnimation->setRotationAt(1, -70); - - QGraphicsItemAnimation *upperLeftLegAnimation = new QGraphicsItemAnimation; - upperLeftLegAnimation->setItem(upperLeftLegItem); - upperLeftLegAnimation->setTimeLine(timeLine); - upperLeftLegAnimation->setRotationAt(0, 150); - upperLeftLegAnimation->setRotationAt(1, 80); - - QGraphicsItemAnimation *lowerLeftLegAnimation = new QGraphicsItemAnimation; - lowerLeftLegAnimation->setItem(lowerLeftLegItem); - lowerLeftLegAnimation->setTimeLine(timeLine); - lowerLeftLegAnimation->setRotationAt(0, 70); - lowerLeftLegAnimation->setRotationAt(1, 10); - - QGraphicsItemAnimation *upperRightLegAnimation = new QGraphicsItemAnimation; - upperRightLegAnimation->setItem(upperRightLegItem); - upperRightLegAnimation->setTimeLine(timeLine); - upperRightLegAnimation->setRotationAt(0, 40); - upperRightLegAnimation->setRotationAt(1, 120); - - QGraphicsItemAnimation *lowerRightLegAnimation = new QGraphicsItemAnimation; - lowerRightLegAnimation->setItem(lowerRightLegItem); - lowerRightLegAnimation->setTimeLine(timeLine); - lowerRightLegAnimation->setRotationAt(0, 10); - lowerRightLegAnimation->setRotationAt(1, 50); - - QGraphicsItemAnimation *torsoAnimation = new QGraphicsItemAnimation; - torsoAnimation->setItem(torsoItem); - torsoAnimation->setTimeLine(timeLine); - torsoAnimation->setRotationAt(0, 5); - torsoAnimation->setRotationAt(1, -20); - - timeLine->setUpdateInterval(1000 / 25); - timeLine->setCurveShape(QTimeLine::SineCurve); - timeLine->setLoopCount(0); - timeLine->setDuration(2000); - timeLine->start(); -} +//! [12] + QParallelAnimationGroup *animation = new QParallelAnimationGroup(this); -Robot::~Robot() -{ - delete timeLine; + QPropertyAnimation *headAnimation = new QPropertyAnimation(headItem, "rotation"); + headAnimation->setStartValue(20); + headAnimation->setEndValue(-20); + QPropertyAnimation *headScaleAnimation = new QPropertyAnimation(headItem, "scale"); + headScaleAnimation->setEndValue(1.1); + animation->addAnimation(headAnimation); + animation->addAnimation(headScaleAnimation); +//! [12] + + QPropertyAnimation *upperLeftArmAnimation = new QPropertyAnimation(upperLeftArmItem, "rotation"); + upperLeftArmAnimation->setStartValue(190); + upperLeftArmAnimation->setEndValue(180); + animation->addAnimation(upperLeftArmAnimation); + + QPropertyAnimation *lowerLeftArmAnimation = new QPropertyAnimation(lowerLeftArmItem, "rotation"); + lowerLeftArmAnimation->setStartValue(50); + lowerLeftArmAnimation->setEndValue(10); + animation->addAnimation(lowerLeftArmAnimation); + + QPropertyAnimation *upperRightArmAnimation = new QPropertyAnimation(upperRightArmItem, "rotation"); + upperRightArmAnimation->setStartValue(300); + upperRightArmAnimation->setEndValue(310); + animation->addAnimation(upperRightArmAnimation); + + QPropertyAnimation *lowerRightArmAnimation = new QPropertyAnimation(lowerRightArmItem, "rotation"); + lowerRightArmAnimation->setStartValue(0); + lowerRightArmAnimation->setEndValue(-70); + animation->addAnimation(lowerRightArmAnimation); + + QPropertyAnimation *upperLeftLegAnimation = new QPropertyAnimation(upperLeftLegItem, "rotation"); + upperLeftLegAnimation->setStartValue(150); + upperLeftLegAnimation->setEndValue(80); + animation->addAnimation(upperLeftLegAnimation); + + QPropertyAnimation *lowerLeftLegAnimation = new QPropertyAnimation(lowerLeftLegItem, "rotation"); + lowerLeftLegAnimation->setStartValue(70); + lowerLeftLegAnimation->setEndValue(10); + animation->addAnimation(lowerLeftLegAnimation); + + QPropertyAnimation *upperRightLegAnimation = new QPropertyAnimation(upperRightLegItem, "rotation"); + upperRightLegAnimation->setStartValue(40); + upperRightLegAnimation->setEndValue(120); + animation->addAnimation(upperRightLegAnimation); + + QPropertyAnimation *lowerRightLegAnimation = new QPropertyAnimation(lowerRightLegItem, "rotation"); + lowerRightLegAnimation->setStartValue(10); + lowerRightLegAnimation->setEndValue(50); + animation->addAnimation(lowerRightLegAnimation); + + QPropertyAnimation *torsoAnimation = new QPropertyAnimation(torsoItem, "rotation"); + torsoAnimation->setStartValue(5); + torsoAnimation->setEndValue(-20); + animation->addAnimation(torsoAnimation); + +//! [13] + for (int i = 0; i < animation->animationCount(); ++i) { + QPropertyAnimation *anim = qobject_cast<QPropertyAnimation *>(animation->animationAt(i)); + anim->setEasingCurve(QEasingCurve::SineCurve); + anim->setDuration(2000); + } + + animation->setLoopCount(-1); + animation->start(); +//! [13] } +//! [9] QRectF Robot::boundingRect() const { return QRectF(); @@ -271,3 +305,4 @@ void Robot::paint(QPainter *painter, Q_UNUSED(option); Q_UNUSED(widget); } +//! [9] diff --git a/examples/graphicsview/dragdroprobot/robot.h b/examples/graphicsview/dragdroprobot/robot.h index 88c4364..f5ff32c 100644 --- a/examples/graphicsview/dragdroprobot/robot.h +++ b/examples/graphicsview/dragdroprobot/robot.h @@ -46,10 +46,11 @@ QT_BEGIN_NAMESPACE class QGraphicsSceneMouseEvent; -class QTimeLine; +class QParallelAnimationGroup; QT_END_NAMESPACE -class RobotPart : public QGraphicsItem +//! [0] +class RobotPart : public QGraphicsObject { public: RobotPart(QGraphicsItem *parent = 0); @@ -59,11 +60,12 @@ protected: void dragLeaveEvent(QGraphicsSceneDragDropEvent *event); void dropEvent(QGraphicsSceneDragDropEvent *event); - QPixmap pixmap; QColor color; bool dragOver; }; +//! [0] +//! [1] class RobotHead : public RobotPart { public: @@ -72,10 +74,16 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - enum { Type = UserType + 1 }; - int type() const; +protected: + void dragEnterEvent(QGraphicsSceneDragDropEvent *event); + void dropEvent(QGraphicsSceneDragDropEvent *event); + +private: + QPixmap pixmap; }; +//! [1] +//! [2] class RobotTorso : public RobotPart { public: @@ -84,7 +92,9 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); }; +//! [2] +//! [3] class RobotLimb : public RobotPart { public: @@ -93,18 +103,17 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); }; +//! [3] +//! [4] class Robot : public RobotPart { public: - Robot(); - ~Robot(); + Robot(QGraphicsItem *parent = 0); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - -private: - QTimeLine *timeLine; }; +//! [4] #endif |