From 98c8e465a62b47051d35f998a3cdea54dfede3ad Mon Sep 17 00:00:00 2001 From: Geir Vattekar Date: Mon, 29 Jun 2009 14:40:17 +0200 Subject: Doc: Documented the Move Blocks example. Reviewed-by: Andreas Aardal Hanssen --- doc/src/examples.qdoc | 1 + doc/src/examples/moveblocks.qdoc | 228 +++++++++++++++++++++++++++++++++ doc/src/images/move-blocks-chart.png | Bin 0 -> 15740 bytes doc/src/images/moveblocks-example.png | Bin 0 -> 4532 bytes examples/animation/moveblocks/main.cpp | 36 +++++- 5 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 doc/src/examples/moveblocks.qdoc create mode 100644 doc/src/images/move-blocks-chart.png create mode 100644 doc/src/images/moveblocks-example.png diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 1f20b91..f6bb877 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -90,6 +90,7 @@ \section1 Animation \list + \o \l{animation/moveblocks}{Move Blocks}\raisedaster \o \l{animation/stickman}{Stick man}\raisedaster \endlist diff --git a/doc/src/examples/moveblocks.qdoc b/doc/src/examples/moveblocks.qdoc new file mode 100644 index 0000000..2bdcca5 --- /dev/null +++ b/doc/src/examples/moveblocks.qdoc @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example animation/moveblocks + \title Move Blocks Example + + The Move Blocks example shows how to animate items in a + QGraphicsScene using a QStateMachine with a custom transition. + + \image moveblocks-example.png + + The example animates the blue blocks that you can see in the image + above. The animation moves the blocks between four preset positions. + + The example consists of the following classes: + + \list + \o \c StateSwitcher inherits QState and can add + \c {StateSwitchTransition}s to other states. + When entered, it will randomly transition to one of these + states. + \o \c StateSwitchTransition is a custom transition that + triggers on \c{StateSwitchEvent}s. + \o \c StateSwitchEvent is a QEvent that trigger \c{StateSwitchTransition}s. + \o \c QGraphicsRectWidget is a QGraphicsWidget that simply + paints its background in a solid \l{Qt::}{blue} color. + \endlist + + The blocks are instances of \c QGraphicsRectWidget and are + animated in a QGraphicsScene. We do this by building a state + graph, which we insert animations into. The graph is then executed + in a QStateMachine. All this is done in \c main(). + Let's look at the \c main() function first. + + \section1 The \c main() Function + + After QApplication has been initialized, we set up the + QGraphicsScene with its \c{QGraphicsRectWidget}s. + + \snippet examples/animation/moveblocks/main.cpp 1 + + After adding the scene to a QGraphicsView, it is time to build the + state graph. Let's first look at a statechart of what we are + trying to build. + + \image move-blocks-chart.png + + Note that the \c group has seven sub states, but we have only + included three of them in the diagram. The code that builds this + graph will be examined line-by-line, and will show how the graph + works. First off, we construct the \c group state: + + \snippet examples/animation/moveblocks/main.cpp 2 + + The timer is used to add a delay between each time the blocks are + moved. The timer is started when \c group is entered. As we will + see later, \c group has a transition back to the \c StateSwitcher + when the timer times out. \c group is the initial state in the + machine, so an animation will be scheduled when the example is + started. + + \snippet examples/animation/moveblocks/main.cpp 3 + \dots + \snippet examples/animation/moveblocks/main.cpp 4 + + \c createGeometryState() returns a QState that will set the + geometry of our items upon entry. It also assigns \c group as the + parent of this state. + + A QPropertyAnimation inserted into a transition will use the + values assigned to a QState (with QState::assignProperty()), i.e., + the animation will interpolate between the current values of the + properties and the values in the target state. We add animated + transitions to the state graph later. + + \snippet examples/animation/moveblocks/main.cpp 5 + + We move the items in parallel. Each item is added to \c + animationGroup, which is the animation that is inserted into the + transitions. + + \snippet examples/animation/moveblocks/main.cpp 6 + + The sequential animation group, \c subGroup, helps us insert a + delay between the animation of each item. + + \snippet examples/animation/moveblocks/main.cpp 7 + \dots + \snippet examples/animation/moveblocks/main.cpp 8 + + A StateSwitchTransition is added to the state switcher + in \c StateSwitcher::addState(). We also add the animation in this + function. Since QPropertyAnimation uses the values from the + states, we can insert the same QPropertyAnimation instance in all + \c {StateSwitchTransition}s. + + As mentioned previously, we add a transition to the state switcher + that triggers when the timer times out. + + \snippet examples/animation/moveblocks/main.cpp 9 + + Finally, we can create the state machine, add our initial state, + and start execution of the state graph. + + \section2 The \c createGemetryState() Function + + In \c createGeometryState(), we set up the geometry for each + graphics item. + + \snippet examples/animation/moveblocks/main.cpp 13 + + As mentioned before, QAbstractTransition will set up an animation + added with \l{QAbstractTransition::}{addAnimation()} using + property values set with \l{QState::}{assignProperty()}. + + \section1 The StateSwitcher Class + + \c StateSwitcher has state switch transitions to each \l{QState}s + we created with \c createGemetryState(). Its job is to transition + to one of these states at random when it is entered. + + All functions in \c StateSwitcher are inlined. We'll step through + its definition. + + \snippet examples/animation/moveblocks/main.cpp 10 + + \c StateSwitcher is a state designed for a particular purpose and + will always be a top-level state. We use \c m_stateCount to keep + track of how many states we are managing, and \c m_lastIndex to + remember which state was the last state to which we transitioned. + + \snippet examples/animation/moveblocks/main.cpp 11 + + We select the next state we are going to transition to, and post a + \c StateSwitchEvent, which we know will trigger the \c + StateSwitchTransition to the selected state. + + \snippet examples/animation/moveblocks/main.cpp 12 + + This is where the magic happens. We assign a number to each state + added. This number is given to both a StateSwitchTransition and to + StateSwitchEvents. As we have seen, state switch events will + trigger a transition with the same number. + + \section1 The StateSwitchTransition Class + + \c StateSwitchTransition inherits QAbstractTransition and triggers + on \c{StateSwitchEvent}s. It contains only inline functions, so + let's take a look at its \l{QAbstractTransition::}{eventTest()} + function, which is the only function that we define.. + + \snippet examples/animation/moveblocks/main.cpp 14 + + \c eventTest is called by QStateMachine when it checks whether a + transition should be triggered--a return value of true means that + it will. We simply check if our assigned number is equal to the + event's number (in which case we fire away). + + \section1 The StateSwitchEvent Class + + \c StateSwitchEvent inherits QEvent, and holds a number that has + been assigned to a state and state switch transition by \c + StateSwitcher. We have already seen how it is used to trigger \c + \c{StateSwitchTransition}s in \c StateSwitcher. + + \snippet examples/animation/moveblocks/main.cpp 15 + + We only have inlined functions in this class, so a look at its + definition will do. + + \section1 The QGraphicsRectWidget Class + + QGraphicsRectWidget inherits QGraphicsWidget and simply paints its + \l{QWidget::}{rect()} blue. We inline \l{QWidget::}{paintEvent()}, + which is the only function we define. Here is the + QGraphicsRectWidget class definition: + + \snippet examples/animation/moveblocks/main.cpp 16 + + \section1 Moving On + + The technique shown in this example works equally well for all + \l{QPropertyAnimation}s. As long as the value to be animated is a + Qt property, you can insert an animation of it into a state graph. + + QState::addAnimation() takes a QAbstractAnimation, so any type + of animation can be inserted into the graph. +*/ + diff --git a/doc/src/images/move-blocks-chart.png b/doc/src/images/move-blocks-chart.png new file mode 100644 index 0000000..fd0c165 Binary files /dev/null and b/doc/src/images/move-blocks-chart.png differ diff --git a/doc/src/images/moveblocks-example.png b/doc/src/images/moveblocks-example.png new file mode 100644 index 0000000..56353d1 Binary files /dev/null and b/doc/src/images/moveblocks-example.png differ diff --git a/examples/animation/moveblocks/main.cpp b/examples/animation/moveblocks/main.cpp index 4843a89..c43e841 100644 --- a/examples/animation/moveblocks/main.cpp +++ b/examples/animation/moveblocks/main.cpp @@ -42,6 +42,7 @@ #include #include +//![15] class StateSwitchEvent: public QEvent { public: @@ -63,8 +64,9 @@ public: private: int m_rand; }; +//![15] - +//![16] class QGraphicsRectWidget : public QGraphicsWidget { public: @@ -74,6 +76,7 @@ public: painter->fillRect(rect(), Qt::blue); } }; +//![16] class StateSwitchTransition: public QAbstractTransition { @@ -85,11 +88,13 @@ public: } protected: +//![14] virtual bool eventTest(QEvent *event) { return (event->type() == QEvent::Type(StateSwitchEvent::StateSwitchType)) && (static_cast(event)->rand() == m_rand); } +//![14] virtual void onTransition(QEvent *) {} @@ -97,6 +102,7 @@ private: int m_rand; }; +//![10] class StateSwitcher : public QState { Q_OBJECT @@ -105,7 +111,9 @@ public: : QState(machine->rootState()), m_machine(machine), m_stateCount(0), m_lastIndex(0) { } +//![10] +//![11] virtual void onEntry(QEvent *) { int n; @@ -115,14 +123,16 @@ public: m_machine->postEvent(new StateSwitchEvent(n)); } virtual void onExit(QEvent *) {} +//![11] +//![12] void addState(QState *state, QAbstractAnimation *animation) { StateSwitchTransition *trans = new StateSwitchTransition(++m_stateCount); trans->setTargetState(state); addTransition(trans); trans->addAnimation(animation); } - +//![12] private: QStateMachine *m_machine; @@ -130,6 +140,7 @@ private: int m_lastIndex; }; +//![13] QState *createGeometryState(QObject *w1, const QRect &rect1, QObject *w2, const QRect &rect2, QObject *w3, const QRect &rect3, @@ -145,6 +156,7 @@ QState *createGeometryState(QObject *w1, const QRect &rect1, return result; } +//![13] int main(int argc, char **argv) { @@ -165,6 +177,7 @@ int main(int argc, char **argv) button3->setObjectName("button3"); button4->setObjectName("button4"); #else +//![1] QGraphicsRectWidget *button1 = new QGraphicsRectWidget; QGraphicsRectWidget *button2 = new QGraphicsRectWidget; QGraphicsRectWidget *button3 = new QGraphicsRectWidget; @@ -178,13 +191,14 @@ int main(int argc, char **argv) scene.addItem(button2); scene.addItem(button3); scene.addItem(button4); - +//![1] QGraphicsView window(&scene); window.setFrameStyle(0); window.setAlignment(Qt::AlignLeft | Qt::AlignTop); window.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); window.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); #endif +//![2] QStateMachine machine; QState *group = new QState(); @@ -193,7 +207,9 @@ int main(int argc, char **argv) timer.setInterval(1250); timer.setSingleShot(true); QObject::connect(group, SIGNAL(entered()), &timer, SLOT(start())); +//![2] +//![3] QState *state1; QState *state2; QState *state3; @@ -207,6 +223,7 @@ int main(int argc, char **argv) button3, QRect(200, 0, 50, 50), button4, QRect(250, 0, 50, 50), group); +//![3] state2 = createGeometryState(button1, QRect(250, 100, 50, 50), button2, QRect(250, 150, 50, 50), button3, QRect(250, 200, 50, 50), @@ -232,13 +249,16 @@ int main(int argc, char **argv) button3, QRect(50, 200, 50, 50), button4, QRect(200, 200, 50, 50), group); +//![4] state7 = createGeometryState(button1, QRect(0, 0, 50, 50), button2, QRect(250, 0, 50, 50), button3, QRect(0, 250, 50, 50), button4, QRect(250, 250, 50, 50), group); group->setInitialState(state1); +//![4] +//![5] QParallelAnimationGroup animationGroup; QSequentialAnimationGroup *subGroup; @@ -246,13 +266,16 @@ int main(int argc, char **argv) anim->setDuration(1000); anim->setEasingCurve(QEasingCurve::OutElastic); animationGroup.addAnimation(anim); +//![5] +//![6] subGroup = new QSequentialAnimationGroup(&animationGroup); subGroup->addPause(100); anim = new QPropertyAnimation(button3, "geometry"); anim->setDuration(1000); anim->setEasingCurve(QEasingCurve::OutElastic); subGroup->addAnimation(anim); +//![6] subGroup = new QSequentialAnimationGroup(&animationGroup); subGroup->addPause(150); @@ -268,21 +291,26 @@ int main(int argc, char **argv) anim->setEasingCurve(QEasingCurve::OutElastic); subGroup->addAnimation(anim); +//![7] StateSwitcher *stateSwitcher = new StateSwitcher(&machine); stateSwitcher->setObjectName("stateSwitcher"); group->addTransition(&timer, SIGNAL(timeout()), stateSwitcher); stateSwitcher->addState(state1, &animationGroup); stateSwitcher->addState(state2, &animationGroup); +//![7] stateSwitcher->addState(state3, &animationGroup); stateSwitcher->addState(state4, &animationGroup); stateSwitcher->addState(state5, &animationGroup); stateSwitcher->addState(state6, &animationGroup); +//![8] stateSwitcher->addState(state7, &animationGroup); +//![8] +//![9] machine.addState(group); machine.setInitialState(group); machine.start(); - +//![9] window.resize(300, 300); window.show(); -- cgit v0.12