×
Namespaces

Variants
Actions
(Difference between revisions)

Archived:Combining Qt Animation and State Machine Frameworks

From Nokia Developer Wiki
Jump to: navigation, search
somnathbanik (Talk | contribs)
somnathbanik (Talk | contribs)
Line 17: Line 17:
 
   
 
   
 
==Animation Framework In Use==
 
==Animation Framework In Use==
Qt’s animation framework is quite interesting and the concepts are easy to understand.  Practically the framework is based on QObjects and Qt’s property system. . The simplest approach is to create a QPropertyAnimation for each property of each QObject we want to animate, and to give the property animation a duration, an initial value, and a final value.  
+
Qt’s animation framework is quite interesting and the concepts are easy to understand.  Practically the framework is based on [http://doc.qt.nokia.com/4.7/qobject.html QObject] and Qt’s property system. The simplest approach is to create a [http://doc.qt.nokia.com/4.7/qpropertyanimation.html QPropertyAnimation] for each property of each [http://doc.qt.nokia.com/4.7/qobject.html QObject] we want to animate, and to give the property animation a duration, an initial value, and a final value.  
In this example we give a duration of 5000 milliseconds and initial and final geometrics specified as QRects. When the animation starts the object is immediately set to the initial geometry and then its geometry will be changed over a 5 second period to reach the final geometry. So if the initial width is 50 pixels and the final width is 360 then the width would be 112 pixels after 1 second,  174 pixels after 2 seconds, 236 pixels after 3 seconds, 298 pixels after 4 seconds and finally 360 pixels after 5 seconds. In this case the increment is 62 pixels per second which is calculated from the difference between the final and initial widths divided by the duration  
+
In this example we give a duration of ''5000 milliseconds'' and initial and final geometrics specified as [http://doc.qt.nokia.com/4.7/qrect.html QRect]. When the animation starts the object is immediately set to the initial geometry and then its geometry will be changed over a 5 second period to reach the final geometry. So if the initial width is ''50'' pixels and the final width is ''360'' then the width would be ''112'' pixels after ''1'' second,  ''174'' pixels after ''2'' seconds,'' 236'' pixels after ''3'' seconds, ''298'' pixels after'' 4'' seconds and finally'' 360'' pixels after ''5'' seconds. In this case the increment is'' 62'' pixels per second which is calculated from the difference between the final and initial widths divided by the duration  
ie (360- 50)/5 = 62.
+
ie ''(360- 50)/5 = 62''.
Qt uses a much more better time granularity then seconds , so the actual change of width might be from 50 pixels to 52 pixels to 54 pixels and so on. We will also use the QEasingCurve class which offers over forty different interpolation graphs.  
+
Qt uses a much more better time granularity then seconds , so the actual change of width might be from'' 50'' pixels to ''52'' pixels to ''54'' pixels and so on. We will also use the [http://doc.qt.nokia.com/4.7/qeasingcurve.html QEasingCurve] class which offers over forty different interpolation graphs.  
 
   
 
   
 
   
 
   
 
   
 
   
 
==State Machine Framework In Use==
 
==State Machine Framework In Use==
Using Qt’s state machine framework we can maintain the state of an application. And like the animation framework is is heavily dependent on QObjects and Qt’s property system. To set up a state machine we start by creating a QStateMachine. Then we create the states we nee (of QState or QFinalState) and for each state we assign property (QObject, property, value), so that the state machine set the property to the given value. Once the states have been set up then we create the transitions which specify how the state machine goes from one state to another. When ever there is a change in the state it emits an exited() signal to the state it left  behind, it emits  entered() signal to the state it enters  and  emits a finished () signal if the state is completed. Now when everything is set up we tell the state machine which state to use as  its initial state and then call QStateMachine::start() to start the things.  There are many functionality of state machine, but here we have used very basic of it.
+
Using Qt’s state machine framework we can maintain the state of an application. And like the animation framework is is heavily dependent on [http://doc.qt.nokia.com/4.7/qobject.html QObject] and Qt’s property system. To set up a state machine we start by creating a [http://doc.qt.nokia.com/4.7/qstatemachine.html QStateMachine]. Then we create the states we nee (of [http://doc.qt.nokia.com/4.7/qstate.html QState] or [http://doc.qt.nokia.com/4.7/qfinalstate.html QFinalState]) and for each state we assign property ''(QObject, property, value)'', so that the state machine set the property to the given value. Once the states have been set up then we create the transitions which specify how the state machine goes from one state to another. When ever there is a change in the state it emits an {{Icode|exited()}} signal to the state it left  behind, it emits  {{Icode|entered()}} signal to the state it enters  and  emits a {{Icode|finished ()}} signal if the state is completed. Now when everything is set up we tell the state machine which state to use as  its initial state and then call {{Icode|QStateMachine::start()}} to start the things.  There are many functionality of state machine, but here we have used very basic of it.
 
   
 
   
 
   
 
   
Line 31: Line 31:
 
   
 
   
 
==Basic Idea==  
 
==Basic Idea==  
To demonstrate the core functionality of the State Machine, we will create an example, where a state machine has three states, s1, s2 and 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 s1, also along with the state change we animate the button from an initial position to a final position.  
+
To demonstrate the core functionality of the State Machine, we will create an example, where a state machine has three states, '''s1''', '''s2''' and '''s3'''. The state machine is controlled by a single [http://doc.qt.nokia.com/4.7/qpushbutton.html QPushButton] when the button is clicked, the machine transitions to another state. Initially, the state machine is in state '''s1''', also along with the state change we animate the button from an initial position to a final position.  
 
   
 
   
 
The three screenshots recorded while changing the states.   
 
The three screenshots recorded while changing the states.   
Line 70: Line 70:
 
#endif // STATEMACHINEQT_H
 
#endif // STATEMACHINEQT_H
 
</code>
 
</code>
The slots animate1/2/3() are used to animate the button from one position to another.  
+
The slots {{Icode|animate1/2/3()}} are used to animate the button from one position to another.  
The QStateMachine class provides a hierarchical finite state machine. QStateMachine is part of The State Machine Framework. The QPropertyAnimation class animates Qt properties.  QPropertyAnimation interpolates over Qt properties. As property values are stored in QVariants, the class inherits QVariantAnimation, and supports animation of the same variant types as its super class.  
+
The [http://doc.qt.nokia.com/4.7/qstatemachine.html QStateMachine] class provides a hierarchical finite state machine. It is part of [http://doc.qt.nokia.com/4.7/statemachine-api.html The State Machine Framework]. The [http://doc.qt.nokia.com/4.7/qpropertyanimation.html QPropertyAnimation] class animates Qt properties.  [http://doc.qt.nokia.com/4.7/qpropertyanimation.html QPropertyAnimation] interpolates over Qt properties. As property values are stored in [http://doc.qt.nokia.com/4.7/qvariant.html#qVariantSetValue QVariants], the class inherits [http://doc.qt.nokia.com/4.7/qvariantanimation.html QVariantAnimation], and supports animation of the same variant types as its super class.  
 
   
 
   
 
   
 
   
Line 96: Line 96:
 
</code>
 
</code>
 
   
 
   
  The QState::assignProperty() function is used to have a state set a property of a QObject when the state is entered.   
+
  The {{Icode|QState::assignProperty()}} function is used to have a state set a property of a [http://doc.qt.nokia.com/4.7/qobject.html QObject] when the state is entered.   
 
   
 
   
 
   
 
   
Then we create the transitions by using the QState::addTransition() function.
+
Then we create the transitions by using the {{Icode|QState::addTransition()}} function.
 
<code cpp>
 
<code cpp>
  s1->addTransition(iButton, SIGNAL(clicked()), s2);
+
    s1->addTransition(iButton, SIGNAL(clicked()), s2);
 
     s2->addTransition(iButton, SIGNAL(clicked()), s3);
 
     s2->addTransition(iButton, SIGNAL(clicked()), s3);
 
     s3->addTransition(iButton, SIGNAL(clicked()), s1);
 
     s3->addTransition(iButton, SIGNAL(clicked()), s1);
Line 119: Line 119:
 
</code>
 
</code>
 
   
 
   
The QState::entered() signal is emitted when the state is entered
+
The {{Icode|QState::entered()}} signal is emitted when the state is entered
 
<code cpp>
 
<code cpp>
 
     QObject::connect(s1, SIGNAL(entered()), this, SLOT(animate1()));
 
     QObject::connect(s1, SIGNAL(entered()), this, SLOT(animate1()));
 
     QObject::connect(s2, SIGNAL(entered()), this, SLOT(animate2()));
 
     QObject::connect(s2, SIGNAL(entered()), this, SLOT(animate2()));
      QObject::connect(s3, SIGNAL(entered()), this, SLOT(animate3()));
+
    QObject::connect(s3, SIGNAL(entered()), this, SLOT(animate3()));
 
</code>
 
</code>
In the following snippet, the  widget animation() slot will be called when states are entered.  
+
In the following snippet, the  widget {{Icode|animation()}} slot will be called when states are entered.  
 
   
 
   
 
   
 
   
 
<code cpp>
 
<code cpp>
  animation = new QPropertyAnimation(iButton, "geometry");
+
        animation = new QPropertyAnimation(iButton, "geometry");
 
         animation->setDuration(5000);
 
         animation->setDuration(5000);
 
         animation->setStartValue(QRect(0,0, iButton->width(),iButton-> height()));
 
         animation->setStartValue(QRect(0,0, iButton->width(),iButton-> height()));
Line 137: Line 137:
 
</code>
 
</code>
 
   
 
   
The button is animated from (0,0) position to (310,135) position while  entering to state 1.  and so as the others. We have also added  an easing effect with setEasingCurve() function. Finally start() is called to start the animation.  
+
The button is animated from ''(0,0)'' position to ''(310,135)'' position while  entering to ''state 1''.  and so as the others. We have also added  an easing effect with {{Icode|setEasingCurve()}} function. Finally {{Icode|start()}} is called to start the animation.  
 
   
 
   
 
   
 
   

Revision as of 17:26, 24 May 2011

Article Metadata
Tested with
Devices(s): N8
Compatibility
Platform(s): Symbian
Symbian
Article
Keywords: QStateMachine, QPropertyAnimation
Created: (24 May 2014)
Last edited: somnathbanik (24 May 2011)


Contents

Overview

This article demonstrate how to combine Animation and State Machine Frameworks. We will see how to implements the application’s logic using a state machine rather than managing it all ourselves. And finally we will add both the animation and state machine frameworks to show how they can be used together, and where the animation is of standard widgets rather than of the graphics items.


Animation Framework In Use

Qt’s animation framework is quite interesting and the concepts are easy to understand. Practically the framework is based on QObject and Qt’s property system. The simplest approach is to create a QPropertyAnimation for each property of each QObject we want to animate, and to give the property animation a duration, an initial value, and a final value. In this example we give a duration of 5000 milliseconds and initial and final geometrics specified as QRect. When the animation starts the object is immediately set to the initial geometry and then its geometry will be changed over a 5 second period to reach the final geometry. So if the initial width is 50 pixels and the final width is 360 then the width would be 112 pixels after 1 second, 174 pixels after 2 seconds, 236 pixels after 3 seconds, 298 pixels after 4 seconds and finally 360 pixels after 5 seconds. In this case the increment is 62 pixels per second which is calculated from the difference between the final and initial widths divided by the duration ie (360- 50)/5 = 62. Qt uses a much more better time granularity then seconds , so the actual change of width might be from 50 pixels to 52 pixels to 54 pixels and so on. We will also use the QEasingCurve class which offers over forty different interpolation graphs.


State Machine Framework In Use

Using Qt’s state machine framework we can maintain the state of an application. And like the animation framework is is heavily dependent on QObject and Qt’s property system. To set up a state machine we start by creating a QStateMachine. Then we create the states we nee (of QState or QFinalState) and for each state we assign property (QObject, property, value), so that the state machine set the property to the given value. Once the states have been set up then we create the transitions which specify how the state machine goes from one state to another. When ever there is a change in the state it emits an exited() signal to the state it left behind, it emits entered() signal to the state it enters and emits a finished () signal if the state is completed. Now when everything is set up we tell the state machine which state to use as its initial state and then call QStateMachine::start() to start the things. There are many functionality of state machine, but here we have used very basic of it.



Basic Idea

To demonstrate the core functionality of the State Machine, we will create an example, where a state machine has three states, s1, s2 and 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 s1, also along with the state change we animate the button from an initial position to a final position.

The three screenshots recorded while changing the states.

StateMachine1.png StateMachine2.png StateMachine3.png

==  Class Definition==
. #ifndef STATEMACHINEQT_H
#define STATEMACHINEQT_H
#include <QMainWindow>
#include "QPushButton"
#include "QVBoxLayout"
#include "QStateMachine"
#include <QPropertyAnimation>
#include "QEventTransition"
#include "QMessageBox"
namespace Ui {
class StateMachineQt;
}
class StateMachineQt : public QMainWindow
{
Q_OBJECT
public:
explicit StateMachineQt(QWidget *parent = 0);
~StateMachineQt();
private:
Ui::StateMachineQt *ui;
public:
QPushButton *iButton;
QStateMachine *machine;
QPropertyAnimation *animation;
public slots:
void animate1();
void animate2();
void animate3();
};
#endif // STATEMACHINEQT_H

The slots animate1/2/3() are used to animate the button from one position to another. The QStateMachine class provides a hierarchical finite state machine. It is part of The State Machine Framework. The QPropertyAnimation class animates Qt properties. QPropertyAnimation interpolates over Qt properties. As property values are stored in QVariants, the class inherits QVariantAnimation, and supports animation of the same variant types as its super class.


Class Implementation

First we create a button of size 50x50.

iButton = new QPushButton(this);
iButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
iButton->setFixedSize(50,50);
iButton->show();
Then we create the state machine and states .
    machine = new QStateMachine(this);
QState *s1 = new QState();
s1->assignProperty(iButton, "text", "S1");
QState *s2 = new QState();
s2->assignProperty(iButton, "text", "S2");
QState *s3 = new QState();
s3->assignProperty(iButton, "text", "S3");
The QState::assignProperty() function is used to have a state set a property of a QObject when the state is entered.  


Then we create the transitions by using the QState::addTransition() function.

    s1->addTransition(iButton, SIGNAL(clicked()), s2);
s2->addTransition(iButton, SIGNAL(clicked()), s3);
s3->addTransition(iButton, SIGNAL(clicked()), s1);
Next, we add the states to the machine and set the machine's initial state:
    machine->addState(s1);
machine->addState(s2);
machine->addState(s3);
machine->setInitialState(s1);

Finally, we start the state machine:

machine->start();

The QState::entered() signal is emitted when the state is entered

    QObject::connect(s1, SIGNAL(entered()), this, SLOT(animate1()));
QObject::connect(s2, SIGNAL(entered()), this, SLOT(animate2()));
QObject::connect(s3, SIGNAL(entered()), this, SLOT(animate3()));

In the following snippet, the widget animation() slot will be called when states are entered.


        animation = new QPropertyAnimation(iButton, "geometry");
animation->setDuration(5000);
animation->setStartValue(QRect(0,0, iButton->width(),iButton-> height()));
animation->setEndValue(QRect(310,135, iButton->width(),iButton->height()));
animation->setEasingCurve(QEasingCurve::OutBounce);
animation->start();

The button is animated from (0,0) position to (310,135) position while entering to state 1. and so as the others. We have also added an easing effect with setEasingCurve() function. Finally start() is called to start the animation.


Source Code

The full source code presented in this article is available here File:StateMachineQt.zip

135 page views in the last 30 days.
×