diff options
Diffstat (limited to 'doc/src')
62 files changed, 967 insertions, 0 deletions
diff --git a/doc/src/animation.qdoc b/doc/src/animation.qdoc new file mode 100644 index 0000000..081660c --- /dev/null +++ b/doc/src/animation.qdoc @@ -0,0 +1,365 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! + \page animation.html + \title The Animation Framework + \ingroup architecture + \ingroup animation + \brief An overview of the Animation Framework + + \keyword Animation + + The animation framework is part of the Kinetic project, and aims + to provide an easy way for creating animated and smooth GUI's. By + animating Qt properties, the framework provides great freedom for + animating widgets and other \l{QObject}s. The framework can also + be used with the Graphics View framework. + + In this overview, we explain the basics of its architecture. We + also show examples of the most common techniques that the + framework allows for animating QObjects and graphics items. + + \tableofcontents + + \section1 The Animation Architecture + + We will in this section take a high-level look at the animation + framework's architecture and how it is used to animate Qt + properties. + + The animation framework foundation consists of the base class + QAbstractAnimation, and its two subclasses QVariantAnimation and + QAnimationGroup. QAbstractAnimation is the ancestor of all + animations. It represents basic properties that are common for all + animations in the framework; notably, the ability to start, stop, + and pause an animation. It is also receives the time change + notifications. + + The animation framework further provides the QPropertyAnimation + class, which inherits QVariantAnimation and performs animation of + a Qt property, which is part of Qt's \l{Meta-Object + System}{meta-object system}. The class performs an interpolation + over the property using an easing curve. So when you want to + animate a value, you can declare it as a property and make your + class a QObject. Note that this gives us great freedom in + animating already existing widgets and other \l{QObject}s. + + Complex animations can be constructed by building a tree structure + of \l{QAbstractAnimation}s. The tree is built by using + \l{QAnimationGroup}s, which function as containers for other + animations. Note also that the groups are subclasses of + QAbstractAnimation, so groups can themselves contain other groups. + + The animation framework can be used on its own, but is also + designed to be part of the state machine framework (See the + \l{The State Machine Framework}{state machine framework} for an + introduction to the Qt state machine). The state machine provides + a special state that can play an animation. A QState can also set + properties when the state is entered or exited, and this special + animation state will interpolate between these values when given a + QPropertyAnimation. We will look more closely at this later. + + Behind the scenes, the animations are controlled by a global + timer, which sends \l{QAbstractAnimation::updateCurrentTime()}{updates} to + all animations that are playing. + + For detailed descriptions of the classes' function and roles in + the framework, please look up their class descriptions. + + \section1 Animating Qt Properties + + As mentioned in the previous section, the QPropertyAnimation class + can interpolate over Qt properties. It is this class that should + be used for animation of values; in fact, its superclass, + QVariantAnimation, is an abstract class, and cannot be used + directly. + + A major reason we chose to animate Qt properties is that it + presents us with freedom to animate already existing classes in + the Qt API. Notably, the QWidget class (which we can also embed in + a QGraphicsView) has properties for its bounds, colors, etc. + Let's look at a small example: + + \code + QPushButton button("Animated Button"); + button.show(); + + QPropertyAnimation animation(&button, "geometry"); + animation.setDuration(10000); + animation.setStartValue(QRect(0, 0, 100, 30)); + animation.setEndValue(QRect(250, 250, 100, 30)); + + animation.start(); + \endcode + + This code will move \c button from the top left corner of the + screen to the position (250, 250). + + The example above will do a linear interpolation between the + start and end value. It is also possible to set values + situated between the start and end value. The interpolation + will then go by these points. + + \code + QPushButton button("Animated Button"); + button.show(); + + QPropertyAnimation animation(&button, "geometry"); + animation.setDuration(10000); + + animation.setKeyValueAt(0, QRect(0, 0, 100, 30)); + animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30)); + animation.setKeyValueAt(1, QRect(0, 0, 100, 30)); + + animation.start(); + \endcode + + In this example, the animation will take the button to (250, 250) + in 8 seconds, and then move it back to its original position in + the remaining 2 seconds. The movement will be linearly + interpolated between these points. + + You also have the possibility to animate values of a QObject + that is not declared as a Qt property. The only requirement is + that this value has a setter. You can then subclass the class + containing the value and declare a property that uses this setter. + Note that all Qt properties requires a getter, so you will need to + provide a getter yourself if this is not defined. + + \code + class MyGraphicsRectItem : public QObject, public QGraphicsRectItem + { + Q_OBJECT + Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) + }; + \endcode + + In the above code example, we subclass QGraphicsRectItem and + define a geometry property. We can now animate the widgets + geometry even if QGraphicsRectItem does not provide the geometry + property. + + For a general introduction to the Qt property system, see its + \l{Qt's Property System}{overview}. + + \section1 Animations and the Graphics View Framework + + When you want to animate \l{QGraphicsItem}s, you also use + QPropertyAnimation. But, unfortunetly, QGraphicsItem does not + inherit QObject. A good solution is to subclass the graphics item + you wish to animate. This class will then also inherit QObject. + This way, QPropertyAnimation can be used for \l{QGraphicsItem}s. + The example below shows how this is done. Another possibility is + to inherit QGraphicsWidget, which already is a QObject. + + \code + class Pixmap : public QObject, public QGraphicsPixmapItem + { + Q_OBJECT + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + ... + \endcode + + As described in the previous section, we need to define + properties that we wish to animate. + + Note that QObject must be the first class inherited as the + meta-object system demands this. + + \warning The QItemAnimation class, which was initially intended + for animating \l{QGraphicsItem}s may be deprecated or removed from + the animation framework. + + \omit (need something about the list of animations). \endomit + + \section1 Easing Curves + + As mentioned, QPropertyAnimation performs an interpolation between + the start and end property value. In addition to adding more key + values to the animation, you can also use an easing curve. Easing + curves describe a function that controls how the speed of the + interpolation between 0 and 1 should be, and are useful if you + want to control the speed of an animation without changing the + path of the interpolation. + + \code + QPushButton button("Animated Button"); + button.show(); + + QPropertyAnimation animation(&button, "geometry"); + animation.setDuration(3000); + animation.setStartValue(QRect(0, 0, 100, 30)); + animation.setEndValue(QRect(250, 250, 100, 30)); + + animation.setEasingCurve(QEasingCurve::OutBounce); + + animation.start(); + \endcode + + Here the animation will follow a curve that makes it bounce like a + ball as if it was dropped from the start to the end position. + QEasingCurve has a large collection of curves for you to choose + from. These are defined by the QEasingCurve::Type enum. If you are + in need of another curve, you can also implement one yourself, and + register it with QEasingCurve. + + \omit Drop this for the first Lab release + (Example of custom easing curve (without the actual impl of + the function I expect) + \endomit + + \section1 Putting Animations Together + + An application will often contain more than one animation. For + instance, you might want to move more than one graphics item + simultaneously or move them in sequence after each other. + + The subclasses of QAnimationGroup (QSequentialAnimationGroup and + QParallelAnimationGroup) are containers for other animations so + that these animations can be animated either in sequence or + parallel. The QAnimationGroup is an example of an animation that + does not animate properties, but it gets notified of time changes + periodically. This enables it to forward those time changes to its + contained animations, and thereby controlling when its animations + are played. + + Let's look at code examples that use both + QSequentialAnimationGroup and QParallelAnimationGroup, starting + off with the latter. + + \code + QPushButton *bonnie = new QPushButton("Bonnie"); + bonnie.show(); + + QPushButton *clyde = new QPushButton("Clyde"); + clyde.show(); + + QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry"); + // Set up anim1 + + QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry"); + // Set up anim2 + + QParallelAnimationGroup *group = new QParallelAnimationGroup; + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + \endcode + + A parallel group plays more than one animation at the same time. + Calling its \l{QAbstractAnimation::}{start()} function will start + all animations it governs. + + \code + QPushButton button("Animated Button"); + button.show(); + + QPropertyAnimation anim1(&button, "geometry"); + anim1.setDuration(3000); + anim1.setStartValue(QRect(0, 0, 100, 30)); + anim1.setEndValue(QRect(500, 500, 100, 30)); + + QPropertyAnimation anim2(&button, "geometry"); + anim2.setDuration(3000); + anim2.setStartValue(QRect(500, 500, 100, 30)); + anim2.setEndValue(QRect(1000, 500, 100, 30)); + + QSequentialAnimationGroup group; + + group.addAnimation(&anim1); + group.addAnimation(&anim2); + + group.start(); + \endcode + + As you no doubt have guessed, QSequentialAnimationGroup plays + its animations in sequence. It starts the next animation in + the list after the previous is finished. + + Since an animation group is an animation itself, you can add + it to another group. This way, you can build a tree structure + of animations which specifies when the animations are played + in relation to each other. + + \section1 Animations and States + + When using a \l{The State Machine Framework}{state machine}, we + have a special state, QAnimationState, that will play one or more + animations. + + The QState::addAnimatedTransition() convenience function lets you + associate an animation to a state transition. The function will + create the QAnimationState for you, and insert it into the state + machine. We also have the possibility to associate properties with + the states rather than setting the start and end values ourselves. + Below is a complete code example that animates the geometry of a + QPushButton. + + \code + QPushButton *button = new QPushButton("Animated Button"); + button->show(); + + QStateMachine *machine = new QStateMachine; + + QState *state1 = new QState(machine->rootState()); + state1->setPropertyOnEntry(button, "geometry", + QRect(0, 0, 100, 30)); + machine->setInitialState(state1); + + QState *state2 = new QState(machine->rootState()); + state2->setPropertyOnEntry(button, "geometry", + QRect(250, 250, 100, 30)); + + state1->addAnimatedTransition(button, SIGNAL(clicked()), state2, + new QPropertyAnimation(button, "geometry")); + state2->addAnimatedTransition(button, SIGNAL(clicked()), state1, + new QPropertyAnimation(button, "geometry")); + + machine->start(); + \endcode + + For a more comprehensive example of how to use the state machine + framework for animations, see the states example (it lives in the + \c{examples/animation/states} directory). +*/ + diff --git a/doc/src/diagrams/programs/easingcurve/easingcurve.pro b/doc/src/diagrams/programs/easingcurve/easingcurve.pro new file mode 100644 index 0000000..0b80127 --- /dev/null +++ b/doc/src/diagrams/programs/easingcurve/easingcurve.pro @@ -0,0 +1,13 @@ +###################################################################### +# Automatically generated by qmake (2.01a) fr 13. feb 13:26:38 2009 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +SOURCES += main.cpp + +CONFIG += console
\ No newline at end of file diff --git a/doc/src/diagrams/programs/easingcurve/main.cpp b/doc/src/diagrams/programs/easingcurve/main.cpp new file mode 100644 index 0000000..98e9d37 --- /dev/null +++ b/doc/src/diagrams/programs/easingcurve/main.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> + +void createCurveIcons(); + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + createCurveIcons(); + return app.exit(); +} + +void createCurveIcons() +{ + QDir dir(QDir::current()); + if (dir.dirName() == QLatin1String("debug") || dir.dirName() == QLatin1String("release")) { + dir.cdUp(); + } + dir.cdUp(); + dir.cdUp(); + dir.cdUp(); + QSize iconSize(128, 128); + QPixmap pix(iconSize); + QPainter painter(&pix); + QLinearGradient gradient(0,0, 0, iconSize.height()); + gradient.setColorAt(0.0, QColor(240, 240, 240)); + gradient.setColorAt(1.0, QColor(224, 224, 224)); + QBrush brush(gradient); + const QMetaObject &mo = QEasingCurve::staticMetaObject; + QMetaEnum metaEnum = mo.enumerator(mo.indexOfEnumerator("Type")); + QFont oldFont = painter.font(); + // Skip QEasingCurve::Custom + QString output(QString::fromAscii("%1/images").arg(dir.absolutePath())); + printf("Generating images to %s\n", qPrintable(output)); + for (int i = 0; i < QEasingCurve::NCurveTypes - 1; ++i) { + painter.setFont(oldFont); + QString name(QLatin1String(metaEnum.key(i))); + painter.fillRect(QRect(QPoint(0, 0), iconSize), brush); + QEasingCurve curve((QEasingCurve::Type)i); + painter.setPen(QColor(0, 0, 255, 64)); + qreal xAxis = iconSize.height()/1.5; + qreal yAxis = iconSize.width()/3; + painter.drawLine(0, xAxis, iconSize.width(), xAxis); // hor + painter.drawLine(yAxis, 0, yAxis, iconSize.height()); // ver + + qreal curveScale = iconSize.height()/2; + + painter.drawLine(yAxis - 2, xAxis - curveScale, yAxis + 2, xAxis - curveScale); // hor + painter.drawLine(yAxis + curveScale, xAxis + 2, yAxis + curveScale, xAxis - 2); // ver + painter.drawText(yAxis + curveScale - 8, xAxis - curveScale - 4, QLatin1String("(1,1)")); + + painter.drawText(yAxis + 42, xAxis + 10, QLatin1String("progress")); + painter.drawText(15, xAxis - curveScale - 10, QLatin1String("ease")); + + painter.setPen(QPen(Qt::red, 1, Qt::DotLine)); + painter.drawLine(yAxis, xAxis - curveScale, yAxis + curveScale, xAxis - curveScale); // hor + painter.drawLine(yAxis + curveScale, xAxis, yAxis + curveScale, xAxis - curveScale); // ver + + QPoint currentPos(yAxis, xAxis); + + painter.setPen(Qt::black); + QFont font = oldFont; + font.setPixelSize(oldFont.pixelSize() + 15); + painter.setFont(font); + painter.drawText(0, iconSize.height() - 20, iconSize.width(), 20, Qt::AlignHCenter, name); + + for (qreal t = 0; t < 1.0; t+=1.0/curveScale) { + QPoint to; + to.setX(yAxis + curveScale * t); + to.setY(xAxis - curveScale * curve.valueForProgress(t)); + painter.drawLine(currentPos, to); + currentPos = to; + } + QString fileName(QString::fromAscii("qeasingcurve-%1.png").arg(name.toLower())); + printf("%s\n", qPrintable(fileName)); + pix.save(QString::fromAscii("%1/%2").arg(output).arg(fileName), "PNG"); + } +} + + diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 29c6c0b..06d7727 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -308,6 +308,12 @@ \o \l{sql/sqlwidgetmapper}{SQL Widget Mapper}\raisedaster \endlist + \section1 State Machine + + \list + \o \l{statemachine/trafficlight}{Traffic Light}\raisedaster + \endlist + \section1 Threads \list diff --git a/doc/src/examples/trafficlight.qdoc b/doc/src/examples/trafficlight.qdoc new file mode 100644 index 0000000..16ee8ad --- /dev/null +++ b/doc/src/examples/trafficlight.qdoc @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/trafficlight + \title Traffic Light Example + + The Traffic Light example shows how to use \l{The State Machine Framework} + to implement the control flow of a traffic light. + + \image trafficlight-example.png + + In this example we write a TrafficLightWidget class. The traffic light has + three lights: Red, yellow and green. The traffic light transitions from + one light to another (red to yellow to green to yellow to red again) at + certain intervals. + + \snippet examples/statemachine/trafficlight/main.cpp 0 + + The LightWidget class represents a single light of the traffic light. It + provides a setOn() function to turn the light on or off. It paints itself + in the color that's passed to the constructor. + + \snippet examples/statemachine/trafficlight/main.cpp 2 + + The TrafficLightWidget class represents the visual part of the traffic + light; it's a widget that contains three lights, and provides accessor + functions for these. + + \snippet examples/statemachine/trafficlight/main.cpp 1 + + The LightState class represents a state that turns a light on when the + state is entered, and off when the state is exited. The class is a timer, + and as we shall see the timeout is used to transition from one LightState + to another. + + \snippet examples/statemachine/trafficlight/main.cpp 3 + + The TrafficLight class combines the TrafficLightWidget with control flow + based on the LightState class. The state graph has four states: + red-to-yellow, yellow-to-green, green-to-yellow and yellow-to-red. The + initial state is red-to-yellow; when the state's timer times out, the + state machine transitions to yellow-to-green. The same process repeats + through the other states. + + \snippet examples/statemachine/trafficlight/main.cpp 4 + + The main() function constructs a TrafficLight and shows it. + +*/ diff --git a/doc/src/external-resources.qdoc b/doc/src/external-resources.qdoc index f48c3d7..3bfb5af 100644 --- a/doc/src/external-resources.qdoc +++ b/doc/src/external-resources.qdoc @@ -334,6 +334,16 @@ */ /*! + \externalpage http://www.w3.org/TR/scxml/ + \title State Chart XML: State Machine Notation for Control Abstraction +*/ + +/*! + \externalpage http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf + \title Statecharts: A visual formalism for complex systems +*/ + +/*! \externalpage http://www.gnu.org/licenses/gpl.html \title GNU General Public License */ diff --git a/doc/src/groups.qdoc b/doc/src/groups.qdoc index c9cedc4..0411c3a 100644 --- a/doc/src/groups.qdoc +++ b/doc/src/groups.qdoc @@ -69,6 +69,18 @@ */ /*! + \group animations + \ingroup groups + + \title Animation Framework + \brief Classes for animations, states and transitions. + + These classes provide a framework for creating both simple and complex + animations. The Animation Framework also provides states and animated + transitions, making it easy to create animated stateful forms. +*/ + +/*! \group abstractwidgets \title Abstract Widget Classes \ingroup groups @@ -597,3 +609,14 @@ These classes are relevant to developers who are working with Qt Script's debugging features. */ + +/*! + \group statemachine + \ingroup groups + + \title State Machine Classes + \brief Classes for constructing and executing state graphs. + + These classes are provided by \l{The State Machine Framework} for creating + event-driven state machines. +*/ diff --git a/doc/src/images/qeasingcurve-cosinecurve.png b/doc/src/images/qeasingcurve-cosinecurve.png Binary files differnew file mode 100644 index 0000000..b27e763 --- /dev/null +++ b/doc/src/images/qeasingcurve-cosinecurve.png diff --git a/doc/src/images/qeasingcurve-inback.png b/doc/src/images/qeasingcurve-inback.png Binary files differnew file mode 100644 index 0000000..8506c0f --- /dev/null +++ b/doc/src/images/qeasingcurve-inback.png diff --git a/doc/src/images/qeasingcurve-inbounce.png b/doc/src/images/qeasingcurve-inbounce.png Binary files differnew file mode 100644 index 0000000..275b38c --- /dev/null +++ b/doc/src/images/qeasingcurve-inbounce.png diff --git a/doc/src/images/qeasingcurve-incirc.png b/doc/src/images/qeasingcurve-incirc.png Binary files differnew file mode 100644 index 0000000..b985e9c --- /dev/null +++ b/doc/src/images/qeasingcurve-incirc.png diff --git a/doc/src/images/qeasingcurve-incubic.png b/doc/src/images/qeasingcurve-incubic.png Binary files differnew file mode 100644 index 0000000..e417ee1 --- /dev/null +++ b/doc/src/images/qeasingcurve-incubic.png diff --git a/doc/src/images/qeasingcurve-incurve.png b/doc/src/images/qeasingcurve-incurve.png Binary files differnew file mode 100644 index 0000000..d9a9340 --- /dev/null +++ b/doc/src/images/qeasingcurve-incurve.png diff --git a/doc/src/images/qeasingcurve-inelastic.png b/doc/src/images/qeasingcurve-inelastic.png Binary files differnew file mode 100644 index 0000000..b242fd3 --- /dev/null +++ b/doc/src/images/qeasingcurve-inelastic.png diff --git a/doc/src/images/qeasingcurve-inexpo.png b/doc/src/images/qeasingcurve-inexpo.png Binary files differnew file mode 100644 index 0000000..f06316c --- /dev/null +++ b/doc/src/images/qeasingcurve-inexpo.png diff --git a/doc/src/images/qeasingcurve-inoutback.png b/doc/src/images/qeasingcurve-inoutback.png Binary files differnew file mode 100644 index 0000000..9fd1446 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutback.png diff --git a/doc/src/images/qeasingcurve-inoutbounce.png b/doc/src/images/qeasingcurve-inoutbounce.png Binary files differnew file mode 100644 index 0000000..fb65f31 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutbounce.png diff --git a/doc/src/images/qeasingcurve-inoutcirc.png b/doc/src/images/qeasingcurve-inoutcirc.png Binary files differnew file mode 100644 index 0000000..123cc54 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutcirc.png diff --git a/doc/src/images/qeasingcurve-inoutcubic.png b/doc/src/images/qeasingcurve-inoutcubic.png Binary files differnew file mode 100644 index 0000000..b07695c --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutcubic.png diff --git a/doc/src/images/qeasingcurve-inoutelastic.png b/doc/src/images/qeasingcurve-inoutelastic.png Binary files differnew file mode 100644 index 0000000..65851e1 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutelastic.png diff --git a/doc/src/images/qeasingcurve-inoutexpo.png b/doc/src/images/qeasingcurve-inoutexpo.png Binary files differnew file mode 100644 index 0000000..7cbfb13 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutexpo.png diff --git a/doc/src/images/qeasingcurve-inoutquad.png b/doc/src/images/qeasingcurve-inoutquad.png Binary files differnew file mode 100644 index 0000000..c5eed06 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutquad.png diff --git a/doc/src/images/qeasingcurve-inoutquart.png b/doc/src/images/qeasingcurve-inoutquart.png Binary files differnew file mode 100644 index 0000000..3b66c0d --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutquart.png diff --git a/doc/src/images/qeasingcurve-inoutquint.png b/doc/src/images/qeasingcurve-inoutquint.png Binary files differnew file mode 100644 index 0000000..c74efe9 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutquint.png diff --git a/doc/src/images/qeasingcurve-inoutsine.png b/doc/src/images/qeasingcurve-inoutsine.png Binary files differnew file mode 100644 index 0000000..5964f31 --- /dev/null +++ b/doc/src/images/qeasingcurve-inoutsine.png diff --git a/doc/src/images/qeasingcurve-inquad.png b/doc/src/images/qeasingcurve-inquad.png Binary files differnew file mode 100644 index 0000000..3373310 --- /dev/null +++ b/doc/src/images/qeasingcurve-inquad.png diff --git a/doc/src/images/qeasingcurve-inquart.png b/doc/src/images/qeasingcurve-inquart.png Binary files differnew file mode 100644 index 0000000..28086d8 --- /dev/null +++ b/doc/src/images/qeasingcurve-inquart.png diff --git a/doc/src/images/qeasingcurve-inquint.png b/doc/src/images/qeasingcurve-inquint.png Binary files differnew file mode 100644 index 0000000..330aa85 --- /dev/null +++ b/doc/src/images/qeasingcurve-inquint.png diff --git a/doc/src/images/qeasingcurve-insine.png b/doc/src/images/qeasingcurve-insine.png Binary files differnew file mode 100644 index 0000000..63d9238 --- /dev/null +++ b/doc/src/images/qeasingcurve-insine.png diff --git a/doc/src/images/qeasingcurve-linear.png b/doc/src/images/qeasingcurve-linear.png Binary files differnew file mode 100644 index 0000000..2a05885 --- /dev/null +++ b/doc/src/images/qeasingcurve-linear.png diff --git a/doc/src/images/qeasingcurve-outback.png b/doc/src/images/qeasingcurve-outback.png Binary files differnew file mode 100644 index 0000000..7cb34c6 --- /dev/null +++ b/doc/src/images/qeasingcurve-outback.png diff --git a/doc/src/images/qeasingcurve-outbounce.png b/doc/src/images/qeasingcurve-outbounce.png Binary files differnew file mode 100644 index 0000000..932fc16 --- /dev/null +++ b/doc/src/images/qeasingcurve-outbounce.png diff --git a/doc/src/images/qeasingcurve-outcirc.png b/doc/src/images/qeasingcurve-outcirc.png Binary files differnew file mode 100644 index 0000000..a1a6cb6 --- /dev/null +++ b/doc/src/images/qeasingcurve-outcirc.png diff --git a/doc/src/images/qeasingcurve-outcubic.png b/doc/src/images/qeasingcurve-outcubic.png Binary files differnew file mode 100644 index 0000000..aa1d604 --- /dev/null +++ b/doc/src/images/qeasingcurve-outcubic.png diff --git a/doc/src/images/qeasingcurve-outcurve.png b/doc/src/images/qeasingcurve-outcurve.png Binary files differnew file mode 100644 index 0000000..a949ae4 --- /dev/null +++ b/doc/src/images/qeasingcurve-outcurve.png diff --git a/doc/src/images/qeasingcurve-outelastic.png b/doc/src/images/qeasingcurve-outelastic.png Binary files differnew file mode 100644 index 0000000..2a9ba39 --- /dev/null +++ b/doc/src/images/qeasingcurve-outelastic.png diff --git a/doc/src/images/qeasingcurve-outexpo.png b/doc/src/images/qeasingcurve-outexpo.png Binary files differnew file mode 100644 index 0000000..e771c2e --- /dev/null +++ b/doc/src/images/qeasingcurve-outexpo.png diff --git a/doc/src/images/qeasingcurve-outinback.png b/doc/src/images/qeasingcurve-outinback.png Binary files differnew file mode 100644 index 0000000..7523727 --- /dev/null +++ b/doc/src/images/qeasingcurve-outinback.png diff --git a/doc/src/images/qeasingcurve-outinbounce.png b/doc/src/images/qeasingcurve-outinbounce.png Binary files differnew file mode 100644 index 0000000..ab73d02 --- /dev/null +++ b/doc/src/images/qeasingcurve-outinbounce.png diff --git a/doc/src/images/qeasingcurve-outincirc.png b/doc/src/images/qeasingcurve-outincirc.png Binary files differnew file mode 100644 index 0000000..ec4b8d3 --- /dev/null +++ b/doc/src/images/qeasingcurve-outincirc.png diff --git a/doc/src/images/qeasingcurve-outincubic.png b/doc/src/images/qeasingcurve-outincubic.png Binary files differnew file mode 100644 index 0000000..8b8ae68 --- /dev/null +++ b/doc/src/images/qeasingcurve-outincubic.png diff --git a/doc/src/images/qeasingcurve-outinelastic.png b/doc/src/images/qeasingcurve-outinelastic.png Binary files differnew file mode 100644 index 0000000..89dde2c --- /dev/null +++ b/doc/src/images/qeasingcurve-outinelastic.png diff --git a/doc/src/images/qeasingcurve-outinexpo.png b/doc/src/images/qeasingcurve-outinexpo.png Binary files differnew file mode 100644 index 0000000..5909901 --- /dev/null +++ b/doc/src/images/qeasingcurve-outinexpo.png diff --git a/doc/src/images/qeasingcurve-outinquad.png b/doc/src/images/qeasingcurve-outinquad.png Binary files differnew file mode 100644 index 0000000..7ddefee --- /dev/null +++ b/doc/src/images/qeasingcurve-outinquad.png diff --git a/doc/src/images/qeasingcurve-outinquart.png b/doc/src/images/qeasingcurve-outinquart.png Binary files differnew file mode 100644 index 0000000..00ef597 --- /dev/null +++ b/doc/src/images/qeasingcurve-outinquart.png diff --git a/doc/src/images/qeasingcurve-outinquint.png b/doc/src/images/qeasingcurve-outinquint.png Binary files differnew file mode 100644 index 0000000..361bfaa4 --- /dev/null +++ b/doc/src/images/qeasingcurve-outinquint.png diff --git a/doc/src/images/qeasingcurve-outinsine.png b/doc/src/images/qeasingcurve-outinsine.png Binary files differnew file mode 100644 index 0000000..1737041 --- /dev/null +++ b/doc/src/images/qeasingcurve-outinsine.png diff --git a/doc/src/images/qeasingcurve-outquad.png b/doc/src/images/qeasingcurve-outquad.png Binary files differnew file mode 100644 index 0000000..6f27cbd --- /dev/null +++ b/doc/src/images/qeasingcurve-outquad.png diff --git a/doc/src/images/qeasingcurve-outquart.png b/doc/src/images/qeasingcurve-outquart.png Binary files differnew file mode 100644 index 0000000..d45a0b8 --- /dev/null +++ b/doc/src/images/qeasingcurve-outquart.png diff --git a/doc/src/images/qeasingcurve-outquint.png b/doc/src/images/qeasingcurve-outquint.png Binary files differnew file mode 100644 index 0000000..6e7df0e --- /dev/null +++ b/doc/src/images/qeasingcurve-outquint.png diff --git a/doc/src/images/qeasingcurve-outsine.png b/doc/src/images/qeasingcurve-outsine.png Binary files differnew file mode 100644 index 0000000..7546a0d --- /dev/null +++ b/doc/src/images/qeasingcurve-outsine.png diff --git a/doc/src/images/qeasingcurve-sinecurve.png b/doc/src/images/qeasingcurve-sinecurve.png Binary files differnew file mode 100644 index 0000000..ca67d44 --- /dev/null +++ b/doc/src/images/qeasingcurve-sinecurve.png diff --git a/doc/src/images/statemachine-button-history.png b/doc/src/images/statemachine-button-history.png Binary files differnew file mode 100644 index 0000000..7f51cae --- /dev/null +++ b/doc/src/images/statemachine-button-history.png diff --git a/doc/src/images/statemachine-button-nested.png b/doc/src/images/statemachine-button-nested.png Binary files differnew file mode 100644 index 0000000..762ac14 --- /dev/null +++ b/doc/src/images/statemachine-button-nested.png diff --git a/doc/src/images/statemachine-button.png b/doc/src/images/statemachine-button.png Binary files differnew file mode 100644 index 0000000..10102bd --- /dev/null +++ b/doc/src/images/statemachine-button.png diff --git a/doc/src/images/statemachine-customevents.png b/doc/src/images/statemachine-customevents.png Binary files differnew file mode 100644 index 0000000..62a4222 --- /dev/null +++ b/doc/src/images/statemachine-customevents.png diff --git a/doc/src/images/statemachine-finished.png b/doc/src/images/statemachine-finished.png Binary files differnew file mode 100644 index 0000000..0ac081d --- /dev/null +++ b/doc/src/images/statemachine-finished.png diff --git a/doc/src/images/statemachine-nonparallel.png b/doc/src/images/statemachine-nonparallel.png Binary files differnew file mode 100644 index 0000000..f9850a7 --- /dev/null +++ b/doc/src/images/statemachine-nonparallel.png diff --git a/doc/src/images/statemachine-parallel.png b/doc/src/images/statemachine-parallel.png Binary files differnew file mode 100644 index 0000000..a65c297 --- /dev/null +++ b/doc/src/images/statemachine-parallel.png diff --git a/doc/src/images/trafficlight-example.png b/doc/src/images/trafficlight-example.png Binary files differnew file mode 100644 index 0000000..3431542 --- /dev/null +++ b/doc/src/images/trafficlight-example.png diff --git a/doc/src/snippets/code/src_corelib_tools_qeasingcurve.cpp b/doc/src/snippets/code/src_corelib_tools_qeasingcurve.cpp new file mode 100644 index 0000000..65358ea --- /dev/null +++ b/doc/src/snippets/code/src_corelib_tools_qeasingcurve.cpp @@ -0,0 +1,4 @@ +//! [0] +qreal myEasingFunction(qreal progress); +//! [0] + diff --git a/doc/src/statemachine.qdoc b/doc/src/statemachine.qdoc new file mode 100644 index 0000000..16eae39 --- /dev/null +++ b/doc/src/statemachine.qdoc @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +/*! + \page statemachine-api.html + \title The State Machine Framework + \brief An overview of the State Machine framework for constructing and executing state graphs. + \ingroup architecture + + \tableofcontents + + The State Machine framework provides classes for creating and executing + state graphs. The concepts and notation are based on those from Harel's + \l{Statecharts: A visual formalism for complex systems}{Statecharts}, which + is also the basis of UML state diagrams. The semantics of state machine + execution are based on \l{State Chart XML: State Machine Notation for + Control Abstraction}{State Chart XML (SCXML)}. + + Statecharts provide a graphical way of modeling how a system reacts to + stimuli. This is done by defining the possible \e states that the system can + be in, and how the system can move from one state to another (\e transitions + between states). A key characteristic of event-driven systems (such as Qt + applications) is that behavior often depends not only on the last or current + event, but also the events that preceded it. With statecharts, this + information is easy to express. + + The State Machine framework provides an API and execution model that can be + used to effectively embed the elements and semantics of statecharts in Qt + applications. The framework integrates tightly with Qt's meta-object system; + for example, transitions between states can be triggered by signals, and + states can be configured to set properties and invoke methods on QObjects. + Qt's event system is used to drive the state machines. + + \section1 A Simple State Machine + + To demonstrate the core functionality of the State Machine API, let's look + at a small example: A state machine with three states, \c s1, \c s2 and \c + s3. The state machine is controlled by a single QPushButton; when the button + is clicked, the machine transitions to another state. Initially, the state + machine is in state \c s1. The statechart for this machine is as follows: + + \img statemachine-button.png + \omit + \caption This is a caption + \endomit + + The following snippet shows the code needed to create such a state machine. + First, we create the state machine and states: + + \code + QStateMachine machine; + QState *s1 = new QState(); + QState *s2 = new QState(); + QState *s3 = new QState(); + \endcode + + Then, we create the transitions by using the QState::addTransition() + function: + + \code + s1->addTransition(button, SIGNAL(clicked()), s2); + s2->addTransition(button, SIGNAL(clicked()), s3); + s3->addTransition(button, SIGNAL(clicked()), s1); + \endcode + + Next, we add the states to the machine and set the machine's initial state: + + \code + machine.addState(s1); + machine.addState(s2); + machine.addState(s3); + machine.setInitialState(s1); + \endcode + + Finally, we start the state machine: + + \code + machine.start(); + \endcode + + The state machine executes asynchronously, i.e. it becomes part of your + application's event loop. + + \section1 Doing Useful Work on State Entry and Exit + + The above state machine merely transitions from one state to another, it + doesn't perform any operations. The QState::assignProperty() function can be + used to have a state set a property of a QObject when the state is + entered. In the following snippet, the value that should be assigned to a + QLabel's text property is specified for each state: + + \code + s1->assignProperty(label, "text", "In state s1"); + s2->assignProperty(label, "text", "In state s2"); + s3->assignProperty(label, "text", "In state s3"); + \endcode + + When any of the states is entered, the label's text will be changed + accordingly. + + The QState::entered() signal is emitted when the state is entered, and the + QState::exited() signal is emitted when the state is exited. In the + following snippet, the button's showMaximized() slot will be called when + state \c s3 is entered, and the button's showMinimized() slot will be called + when \c s3 is exited: + + \code + QObject::connect(s3, SIGNAL(entered()), button, SLOT(showMaximized())); + QObject::connect(s3, SIGNAL(exited()), button, SLOT(showMinimized())); + \endcode + + \section1 State Machines That Finish + + The state machine defined in the previous section never finishes. In order + for a state machine to be able to finish, it needs to have a top-level \e + final state (QFinalState object). When the state machine enters a top-level + final state, the machine will emit the QStateMachine::finished() signal and + halt. + + \section1 Sharing Transitions By Grouping States + + Assume we wanted the user to be able to quit the application at any time by + clicking a Quit button. In order to achieve this, we need to create a final + state and make it the target of a transition associated with the Quit + button's clicked() signal. We could add a transition from each of \c s1, \c + s2 and \c s3; however, this seems redundant, and one would also have to + remember to add such a transition from every new state that is added in the + future. + + We can achieve the same behavior (namely that clicking the Quit button quits + the state machine, regardless of which state the state machine is in) by + grouping states \c s1, \c s2 and \c s3. This is done by creating a new + top-level state and making the three original states children of the new + state. The following diagram shows the new state machine. + + \img statemachine-button-nested.png + \omit + \caption This is a caption + \endomit + + The three original states have been renamed \c s11, \c s12 and \c s13 to + reflect that they are now children of the new top-level state, \c s1. Child + states implicitly inherit the transitions of their parent state. This means + it is now sufficient to add a single transition from \c s1 to the final + state \c s2. New states added to \c s1 will also automatically inherit this + transition. + + All that's needed to group states is to specify the proper parent when the + state is created. You also need to specify which of the child states is the + initial one (i.e. which child state the state machine should enter when the + parent state is the target of a transition). + + \code + QState *s1 = new QState(); + QState *s11 = new QState(s1); + QState *s12 = new QState(s1); + QState *s13 = new QState(s1); + s1->setInitialState(s11); + machine.addState(s1); + \endcode + + \code + QFinalState *s2 = new QFinalState(); + s1->addTransition(quitButton, SIGNAL(clicked()), s2); + machine.addState(s2); + + QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit())); + \endcode + + In this case we want the application to quit when the state machine is + finished, so the machine's finished() signal is connected to the + application's quit() slot. + + A child state can override an inherited transition. For example, the + following code adds a transition that effectively causes the Quit button to + be ignored when the state machine is in state \c s12. + + \code + s12>addTransition(quitButton, SIGNAL(clicked()), s12); + \endcode + + A transition can have any state as its target, i.e. the target state does + not have to be on the same level in the state hierarchy as the source state. + + \section1 Using History States to Save and Restore the Current State + + Imagine that we wanted to add an "interrupt" mechanism to the example + discussed in the previous section; the user should be able to click a button + to have the state machine perform some non-related task, after which the + state machine should resume whatever it was doing before (i.e. return to the + old state, which is one of \c s11, \c s12 and \c s13 in this case). + + Such behavior can easily be modeled using \e{history states}. A history + state (QHistoryState object) is a pseudo-state that represents the child + state that the parent state was in the last time the parent state was + exited. + + A history state is created as a child of the state for which we wish to + record the current child state; when the state machine detects the presence + of such a state at runtime, it automatically records the current (real) + child state when the parent state is exited. A transition to the history + state is in fact a transition to the child state that the state machine had + previously saved; the state machine automatically "forwards" the transition + to the real child state. + + The following diagram shows the state machine after the interrupt mechanism + has been added. + + \img statemachine-button-history.png + \omit + \caption This is a caption + \endomit + + The following code shows how it can be implemented; in this example we + simply display a message box when \c s3 is entered, then immediately return + to the previous child state of \c s1 via the history state. + + \code + QHistoryState *s1h = s1->addHistoryState(); + + QState *s3 = new QState(); + s3->assignProperty(label, "text", "In s3"); + QMessageBox mbox; + mbox.addButton(QMessageBox::Ok); + mbox.setText("Interrupted!"); + mbox.setIcon(QMessageBox::Information); + QObject::connect(s3, SIGNAL(entered()), &mbox, SLOT(exec())); + s3->addTransition(s1h); + machine.addState(s3); + + s1->addTransition(interruptButton, SIGNAL(clicked()), s3); + \endcode + + \section1 Using Parallel States to Avoid a Combinatorial Explosion of States + + Assume that you wanted to model a set of mutually exclusive properties of a + car in a single state machine. Let's say the properties we are interested in + are Clean vs Dirty, and Moving vs Not moving. It would take four mutually + exclusive states and eight transitions to be able to represent and freely + move between all possible combinations. + + \img statemachine-nonparallel.png + \omit + \caption This is a caption + \endomit + + If we added a third property (say, Red vs Blue), the total number of states + would double, to eight; and if we added a fourth property (say, Enclosed vs + Convertible), the total number of states would double again, to 16. + + Using parallel states, the total number of states and transitions grows + linearly as we add more properties, instead of exponentially. Furthermore, + states can be added to or removed from the parallel state without affecting + any of their sibling states. + + \img statemachine-parallel.png + \omit + \caption This is a caption + \endomit + + To create a parallel state group, pass QState::ParallelStates to the QState + constructor. + + \code + QState *s1 = new QState(QState::ParallelStates); + // s11 and s12 will be entered in parallel + QState *s11 = new QState(s1); + QState *s12 = new QState(s1); + \endcode + + When a parallel state group is entered, all its child states will be + simultaneously entered. Transitions within the individual child states + operate normally. However, any of the child states may take a transition + outside the parent state. When this happens, the parent state and all of its + child states are exited. + + \section1 Detecting that a Composite State has Finished + + A child state can be final (a QFinalState object); when a final child state + is entered, the parent state emits the QState::finished() signal. + + \img statemachine-finished.png + \omit + \caption This is a caption + \endomit + + This is useful when you want to hide the internal details of a state; + i.e. the only thing the outside world should be able to do is enter the + state, and get a notification when the state has completed its work. + + For parallel state groups, the QState::finished() signal is emitted when \e + all the child states have entered final states. + + \section1 Events, Transitions and Guards + + A QStateMachine runs its own event loop. For signal transitions + (QSignalTransition objects), QStateMachine automatically posts a + QSignalEvent to itself when it intercepts the corresponding signal; + similarly, for QObject event transitions (QEventTransition objects) a + QWrappedEvent is posted. + + You can post your own events to the state machine using + QStateMachine::postEvent(). + + When posting a custom event to the state machine, you typically also have + one or more custom transitions that can be triggered from events of that + type. To create such a transition, you subclass QAbstractTransition and + reimplement QAbstractTransition::eventTest(), where you check if an event + matches your event type (and optionally other criteria, e.g. attributes of + the event object). + + Here we define our own custom event type, \c StringEvent, for posting + strings to the state machine: + + \code + struct StringEvent : public QEvent + { + StringEvent(const QString &val) + : QEvent(QEvent::Type(QEvent::User+1)), + value(val) {} + + QString value; + }; + \endcode + + Next, we define a transition that only triggers when the event's string + matches a particular string (a \e guarded transition): + + \code + class StringTransition : public QAbstractTransition + { + public: + StringTransition(const QString &value) + : m_value(value) {} + + protected: + virtual bool eventTest(QEvent *e) const + { + if (e->type() != QEvent::Type(QEvent::User+1)) // StringEvent + return false; + StringEvent *se = static_cast<StringEvent*>(e); + return (m_value == se->value); + } + + virtual void onTransition(QEvent *) {} + + private: + QString m_value; + }; + \endcode + + In the eventTest() reimplementation, we first check if the event type is the + desired one; if so, we cast the event to a StringEvent and perform the + string comparison. + + The following is a statechart that uses the custom event and transition: + + \img statemachine-customevents.png + \omit + \caption This is a caption + \endomit + + Here's what the implementation of the statechart looks like: + + \code + QStateMachine machine; + QState *s1 = new QState(); + QState *s2 = new QState(); + QFinalState *done = new QFinalState(); + + StringTransition *t1 = new StringTransition("Hello"); + t1->setTargetState(s2); + s1->addTransition(t1); + StringTransition *t2 = new StringTransition("world"); + t2->setTargetState(done); + s2->addTransition(t2); + + machine.addState(s1); + machine.addState(s2); + machine.addState(done); + machine.setInitialState(s1); + \endcode + + Once the machine is started, we can post events to it. + + \code + machine.postEvent(new StringEvent("Hello")); + machine.postEvent(new StringEvent("world")); + \endcode +*/ |