QML States Controlling: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
'''English'''<br />
[[Category:Developing_with_Qt::Qt Quick]] [[Category:HowTo]]<br />'''English'''<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]


=<span class="caps">QML</span> States Controlling=
= QML States Controlling =


==Introduction==
== Introduction ==


<span class="caps">QML</span> offers very powerful [http://doc.qt.io/qt-4.8/qml-state.html constructs] ''[qt.io]'' to model states and dynamic behaviors. We refer to a state as a collection of parameters describing an entity at a given moment. The behavior of the entity could be described as a sequence of changing states. The model known as Finite State Machine (<span class="caps">FSM</span>) is widely used in many domains including the computer sciences also. For a painless introduction see [http://lamsonproject.org/docs/introduction_to_finite_state_machines.html here] ''[lamsonproject.org]'' and [http://ai-depot.com/FiniteStateMachines/ here] ''[ai-depot.com]''.
QML offers very powerful &quot;constructs&amp;quot;:http://doc.qt.io/qt-4.8/qml-state.html to model states and dynamic behaviors. We refer to a state as a collection of parameters describing an entity at a given moment. The behavior of the entity could be described as a sequence of changing states. The model known as Finite State Machine (FSM) is widely used in many domains including the computer sciences also. For a painless introduction see &quot;here&amp;quot;:http://lamsonproject.org/docs/introduction_to_finite_state_machines.html and &quot;here&amp;quot;:http://ai-depot.com/FiniteStateMachines/.


In this article we are analyzing a more complicated state machine model, which has states that are state machine by their self. At the beginning we summarize the <span class="caps">QML</span> states constructs and some techniques for their control that we need for implementation. In the main article part we discuss a <span class="caps">QML</span> implementation of the considered <span class="caps">FSM</span> model. The analysis highlights the <span class="caps">QML</span> ''States/Transition'' elements also.
In this article we are analyzing a more complicated state machine model, which has states that are state machine by their self. At the beginning we summarize the QML states constructs and some techniques for their control that we need for implementation. In the main article part we discuss a QML implementation of the considered FSM model. The analysis highlights the QML ''States/Transition'' elements also.


The simplest <span class="caps">FSM</span> model could be viewed as a sequencer. Starting from an initial state the states are navigated in a linear manner – one by one in preliminary defined ordering. The transition diagram known as state transition diagram is illustrated bellow:
The simplest FSM model could be viewed as a sequencer. Starting from an initial state the states are navigated in a linear manner – one by one in preliminary defined ordering. The transition diagram known as state transition diagram is illustrated bellow:


[[Image:sequencer.jpg|sequencer state diagram]] Simple Sequencer State Diagram
[[Image:http://i1072.photobucket.com/albums/w362/vabo123/sequencer.jpg|sequencer state diagram]]<br /> Simple Sequencer State Diagram


The <span class="caps">FSM</span> model we are going to implement supposes that some of states have branches:
The FSM model we are going to implement supposes that some of states have branches:


[[Image:brancher.jpg|brancher state diagram]]
[[Image:http://i1072.photobucket.com/albums/w362/vabo123/brancher.jpg|brancher state diagram]]


Sequencer with Branches State Diagram
Sequencer with Branches State Diagram


Entering such a state causes activating of its internal state machine. Completing this <span class="caps">FSM</span><br /> we return to the next state of the <span class="caps">FSM</span> at global level. This model could be referred to as a sequencer with nested <span class="caps">FSM</span>s.
Entering such a state causes activating of its internal state machine. Completing this FSM<br />we return to the next state of the FSM at global level. This model could be referred to as a sequencer with nested FSMs.


==<span class="caps">QML</span> States==
== QML States ==


===More States Definitions===
=== More States Definitions ===


In <span class="caps">QML</span> each state is identified by its name, which is of ''String'' type. Having several states defined, we could store their names in a ''variant'' property like that:
In QML each state is identified by its name, which is of ''String'' type. Having several states defined, we could store their names in a ''variant'' property like that:
 
<code><br />import QtQuick 1.1<br />Rectangle {id:top1<br /> width: 100<br /> height: 100<br /> color:&quot;red&amp;quot;<br />property variant statesNames:[&quot;state1&amp;quot;,&quot;state2&amp;quot;]<br />property int counter:0<br /> states:[<br /> State {<br /> name:&quot;state1&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;pink&amp;quot;}<br /> },<br /> State {<br /> name:&quot;state2&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;yellow&amp;quot;}<br /> }<br /> ]<br /> Timer {id:zen<br /> interval: 2000; running: true; repeat: true<br /> onTriggered: {<br /> if(counter&amp;lt;2){<br /> top1.state=statesNames[counter]<br /> counter=counter+1<br /> }<br /> else<br /> Qt.quit()<br /> }<br /> }<br />}<br /></code>


If we have actions associated with a state we could use ''StateChangeScript'' element, which offers a script block.
If we have actions associated with a state we could use ''StateChangeScript'' element, which offers a script block.


===Nested variant Types===
=== Nested variant Types ===


As we know, ''variant'' type acts as a list. Now suppose that an element of a ''variant'' property is also of ''variant'' type:
As we know, ''variant'' type acts as a list. Now suppose that an element of a ''variant'' property is also of ''variant'' type:
<code><br />Rectangle {<br /> width: 360<br /> height: 360<br /> property variant nestedStrings:[&quot;first&amp;quot;,&quot;second&amp;quot;]<br /> property variant sequence :[&quot;element1&amp;quot;,nestedStrings,&quot;element3&amp;quot;]<br /> Component.onCompleted: {<br /> console.log(sequence[2])<br /> console.log(&quot;nested elements&amp;quot;,sequence[1][0])<br /> }<br />}<br /></code>


Further, we could define in a ''variant'' list definition that an element is also a list using square brackets like that:
Further, we could define in a ''variant'' list definition that an element is also a list using square brackets like that:
<code><br />property variant listIntoList:[ [&quot;string1&amp;quot;],[&quot;string21&amp;quot;,&quot;string22&amp;quot;],[&quot;string3&amp;quot;] ]<br /></code>


The nested list elements are accessed this way:
The nested list elements are accessed this way:


==<span class="caps">FSM</span> Model Implementation==
<code><br />listIntoList[1][1]<br /></code>


We are considering a <span class="caps">FSM</span> that has 5 states. The states 1, 3 and 5 have no internal states. The states 2 and 4 have internal states – 5 states each.
== FSM Model Implementation ==


===Definition of States===
We are considering a FSM that has 5 states. The states 1, 3 and 5 have no internal states. The states 2 and 4 have internal states – 5 states each.


The states set is defined in a <span class="caps">QML</span> element (e.g. ''Rectangle'') starting from first state (its branch if any), second state (its branch if any), etc. The states are members of <span class="caps">QML</span> ''states'' property. Note that states names are global and visible in the rectangle scope. The goal of this definition is to introduce the states identifiers and actions associated with states (use ''StateChangeScript'' element).
=== Definition of States ===


===Ordering of States===
The states set is defined in a QML element (e.g. ''Rectangle'') starting from first state (its branch if any), second state (its branch if any), etc. The states are members of QML ''states'' property. Note that states names are global and visible in the rectangle scope. The goal of this definition is to introduce the states identifiers and actions associated with states (use ''StateChangeScript'' element).
 
=== Ordering of States ===


The states names are arranged in a ''variant'' type property following the next rules:
The states names are arranged in a ''variant'' type property following the next rules:
Line 54: Line 62:


- All states (on global level as well as nested ones) are accessed this way:
- All states (on global level as well as nested ones) are accessed this way:
<code>Property_name [][]<code>


Where the first index controls global states and the second one controls states in the corresponding branch (if any).
Where the first index controls global states and the second one controls states in the corresponding branch (if any).
Line 59: Line 69:
The following diagram illustrates the above definitions:
The following diagram illustrates the above definitions:


[[Image:nestedStates.jpg|nested states]]
[[Image:http://i1072.photobucket.com/albums/w362/vabo123/nestedStates.jpg|nested states]]


==Implementation Details==
</code>property variant stateOrder :[[state1],[state21,state22],[state3],<br /> [state41,state42,state43],[state5]]<br /> stateOrder[1][1] //refers to state22<code>


The demo code is available [http://bit.ly/1fzD7JO here] ''[bit.ly]''. The code is not optimized to easy explanation of basic ideas. A fragment of implementation follows:
== Implementation Details ==


A ''Timer'' element is used to initiate the transition from the current state to the next one. Each state is represented visually by different images. The actions performed for each state are included in a ''StateChangesScript'' element block. There are three types of actions – changing the color of the frame containing the images, changing the images and altering the explanatory text in the upper text box.
The demo code is available &quot;here&amp;quot;:http://bit.ly/1fzD7JO. The code is not optimized to easy explanation of basic ideas. A fragment of implementation follows:


The states are visited one by one. You may change the ''Timer interval'' property to control the rate of images rendering. The transition is implemented changing the property ''state'' of <span class="caps">QML</span> state [http://doc.qt.io/qt-4.8/qdeclarativestates.html model] ''[qt.io]''.
</code><br />Rectangle {id:top1<br /> width: 500<br /> height: 500<br /> color:&quot;#f9f0e7&amp;quot;<br /> property bool branch //Controls if a state has a branch<br /> property int currentIndex:0 //Current index for outer loop<br /> property int innerCounter:0 //Current index for inner (branch) loop<br /> //statesParameters property holds two parameters for each state:<br /> // a bool value if a state has or has no branch and the number<br /> // of states in a branch<br /> property variant statesParameters:[ [true,5],[false,1],[true,5],[false,1],[true,5] ]<br /> //Images could be stored in a list<br /> property variant imagesList: [ [&quot;kiparisi/kip1.jpg&amp;quot;,&quot;kiparisi/piramidalen.jpg&amp;quot;,<br /> &quot;kiparisi/spiral.jpg&amp;quot;,&quot;kiparisi/tuya.jpg&amp;quot;,&quot;kiparisi/septe.jpg&amp;quot;] ]<br /> //A rectangle that contains explanatory text is added<br /> Rectangle {id:frame<br /> x:60;y:60<br /> width:350; height:30<br /> color:&quot;white&amp;quot;<br /> Rectangle {<br /> Text {id:literal<br /> text: &quot;This is the initial state. A timer generates state transitions.&quot;<br /> }<br /> }<br /> }<br /> Rectangle {<br /> x:180;y:180<br /> Image {id:picture; source:&quot;Qt_logo.jpg&amp;quot;}<br /> }<br /> property variant stateNames:[ [&quot;state11&amp;quot;,&quot;state12&amp;quot;,&quot;state13&amp;quot;,&quot;state14&amp;quot;,&quot;state15&amp;quot;],<br /> [&quot;state2&amp;quot;],<br /> [&quot;state31&amp;quot;,&quot;state32&amp;quot;,&quot;state33&amp;quot;,&quot;state34&amp;quot;,&quot;state35&amp;quot;],<br /> [&quot;state4&amp;quot;],<br /> [&quot;state51&amp;quot;,&quot;state52&amp;quot;,&quot;state53&amp;quot;,&quot;state54&amp;quot;,&quot;state55&amp;quot;]<br /> ]<br /> property int counter:0<br /> Timer {id:zen<br /> interval: 2000; running: true; repeat: true<br /> onTriggered: {<br /> if(counter&amp;lt;5)<br /> branch=statesParameters[counter][0];<br /> else<br /> Qt.quit();<br /> if(branch==false)<br /> {<br /> innerCounter=0;<br /> top1.state=stateNames[counter][innerCounter];<br /> counter=counter+1;<br /> currentIndex=counter;<br /> }<br /> else<br /> {<br /> if(innerCounter&amp;lt;statesParameters[counter][1])<br /> {<br /> top1.state=stateNames[counter][innerCounter];<br /> innerCounter=innerCounter+1;<br /> }<br /> else{<br /> counter=currentIndex+1;<br /> if(counter&amp;gt;=5) Qt.quit();<br /> }<br /> }<br /> }//end of onTriggered<br /> }// end of Timer<br /> states:[<br /> State {<br /> name:&quot;state11&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;Snow&amp;quot;}<br /> StateChangeScript {<br /> name:&quot;stateScript11&amp;quot;<br /> script:{<br /> literal.text=&quot;Cupressaceae - State 11&amp;quot;<br /> picture.source=imagesList[0][2]<br /> }<br /> }<br /> },<br /> State {<br /> name:&quot;state12&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;Azure&amp;quot;}<br /> StateChangeScript {<br /> name:&quot;stateScript12&amp;quot;<br /> script:{<br /> literal.text=&quot;Cupressaceae - State 12&amp;quot;<br /> picture.source=imagesList[0][0]<br /> }<br /> }<br /> },<br />. . .


There are two indexes controlling the transition between states. The ''innerCounter'' property controls transitions in a branch and the ''counter'' property manages transitions at the global level.
State {<br /> name:&quot;state55&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;PeachPuff&amp;quot;}<br /> StateChangeScript {<br /> name:&quot;stateScript55&amp;quot;<br /> script:{<br /> literal.text=&quot;Roses - State55&amp;quot;<br /> picture.source=&quot;roses/katerach.jpg&amp;quot;<br /> }<br /> }<br /> }<br /> ]<br />}//end of top1<br /><code>


===Categories:===
A ''Timer'' element is used to initiate the transition from the current state to the next one. Each state is represented visually by different images. The actions performed for each state are included in a ''StateChangesScript'' element block. There are three types of actions – changing the color of the frame containing the images, changing the images and altering the explanatory text in the upper text box.


* [[:Category:Developing with Qt|Developing_with_Qt]]
The states are visited one by one. You may change the ''Timer interval'' property to control the rate of images rendering. The transition is implemented changing the property ''state'' of QML state &quot;model&amp;quot;:http://doc.qt.io/qt-4.8/qdeclarativestates.html.
** [[:Category:Developing with Qt::Qt-Quick|Qt Quick]]
* [[:Category:HowTo|HowTo]]

Revision as of 14:36, 23 February 2015


English
[toc align_right="yes&quot; depth="3&quot;]

QML States Controlling

Introduction

QML offers very powerful "constructs&quot;:http://doc.qt.io/qt-4.8/qml-state.html to model states and dynamic behaviors. We refer to a state as a collection of parameters describing an entity at a given moment. The behavior of the entity could be described as a sequence of changing states. The model known as Finite State Machine (FSM) is widely used in many domains including the computer sciences also. For a painless introduction see "here&quot;:http://lamsonproject.org/docs/introduction_to_finite_state_machines.html and "here&quot;:http://ai-depot.com/FiniteStateMachines/.

In this article we are analyzing a more complicated state machine model, which has states that are state machine by their self. At the beginning we summarize the QML states constructs and some techniques for their control that we need for implementation. In the main article part we discuss a QML implementation of the considered FSM model. The analysis highlights the QML States/Transition elements also.

The simplest FSM model could be viewed as a sequencer. Starting from an initial state the states are navigated in a linear manner – one by one in preliminary defined ordering. The transition diagram known as state transition diagram is illustrated bellow:

sequencer state diagram
Simple Sequencer State Diagram

The FSM model we are going to implement supposes that some of states have branches:

brancher state diagram

Sequencer with Branches State Diagram

Entering such a state causes activating of its internal state machine. Completing this FSM
we return to the next state of the FSM at global level. This model could be referred to as a sequencer with nested FSMs.

QML States

More States Definitions

In QML each state is identified by its name, which is of String type. Having several states defined, we could store their names in a variant property like that:

<br />import QtQuick 1.1<br />Rectangle {id:top1<br /> width: 100<br /> height: 100<br /> color:&quot;red&amp;quot;<br />property variant statesNames:[&quot;state1&amp;quot;,&quot;state2&amp;quot;]<br />property int counter:0<br /> states:[<br /> State {<br /> name:&quot;state1&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;pink&amp;quot;}<br /> },<br /> State {<br /> name:&quot;state2&amp;quot;<br /> PropertyChanges {target:top1;color:&quot;yellow&amp;quot;}<br /> }<br /> ]<br /> Timer {id:zen<br /> interval: 2000; running: true; repeat: true<br /> onTriggered: {<br /> if(counter&amp;lt;2){<br /> top1.state=statesNames[counter]<br /> counter=counter+1<br /> }<br /> else<br /> Qt.quit()<br /> }<br /> }<br />}<br />

If we have actions associated with a state we could use StateChangeScript element, which offers a script block.

Nested variant Types

As we know, variant type acts as a list. Now suppose that an element of a variant property is also of variant type:

<br />Rectangle {<br /> width: 360<br /> height: 360<br /> property variant nestedStrings:[&quot;first&amp;quot;,&quot;second&amp;quot;]<br /> property variant sequence :[&quot;element1&amp;quot;,nestedStrings,&quot;element3&amp;quot;]<br /> Component.onCompleted: {<br /> console.log(sequence[2])<br /> console.log(&quot;nested elements&amp;quot;,sequence[1][0])<br /> }<br />}<br />

Further, we could define in a variant list definition that an element is also a list using square brackets like that:

<br />property variant listIntoList:[ [&quot;string1&amp;quot;],[&quot;string21&amp;quot;,&quot;string22&amp;quot;],[&quot;string3&amp;quot;] ]<br />

The nested list elements are accessed this way:

<br />listIntoList[1][1]<br />

FSM Model Implementation

We are considering a FSM that has 5 states. The states 1, 3 and 5 have no internal states. The states 2 and 4 have internal states – 5 states each.

Definition of States

The states set is defined in a QML element (e.g. Rectangle) starting from first state (its branch if any), second state (its branch if any), etc. The states are members of QML states property. Note that states names are global and visible in the rectangle scope. The goal of this definition is to introduce the states identifiers and actions associated with states (use StateChangeScript element).

Ordering of States

The states names are arranged in a variant type property following the next rules:

- If a state has a branch it is defined in the list as a nested list.

- If a state has no branch it is defined in the list as a nested list with one element only.

- All states (on global level as well as nested ones) are accessed this way:

Property_name [][]<code>

Where the first index controls global states and the second one controls states in the corresponding branch (if any).

The following diagram illustrates the above definitions:

[[Image:http://i1072.photobucket.com/albums/w362/vabo123/nestedStates.jpg|nested states]]

property variant stateOrder :[[state1],[state21,state22],[state3],
[state41,state42,state43],[state5]]
stateOrder[1][1] //refers to state22

== Implementation Details ==

The demo code is available &quot;here&amp;quot;:http://bit.ly/1fzD7JO. The code is not optimized to easy explanation of basic ideas. A fragment of implementation follows:


Rectangle {id:top1
width: 500
height: 500
color:"#f9f0e7&quot;
property bool branch //Controls if a state has a branch
property int currentIndex:0 //Current index for outer loop
property int innerCounter:0 //Current index for inner (branch) loop
//statesParameters property holds two parameters for each state:
// a bool value if a state has or has no branch and the number
// of states in a branch
property variant statesParameters:[ [true,5],[false,1],[true,5],[false,1],[true,5] ]
//Images could be stored in a list
property variant imagesList: [ ["kiparisi/kip1.jpg&quot;,"kiparisi/piramidalen.jpg&quot;,
"kiparisi/spiral.jpg&quot;,"kiparisi/tuya.jpg&quot;,"kiparisi/septe.jpg&quot;] ]
//A rectangle that contains explanatory text is added
Rectangle {id:frame
x:60;y:60
width:350; height:30
color:"white&quot;
Rectangle {
Text {id:literal
text: "This is the initial state. A timer generates state transitions."
}
}
}
Rectangle {
x:180;y:180
Image {id:picture; source:"Qt_logo.jpg&quot;}
}
property variant stateNames:[ ["state11&quot;,"state12&quot;,"state13&quot;,"state14&quot;,"state15&quot;],
["state2&quot;],
["state31&quot;,"state32&quot;,"state33&quot;,"state34&quot;,"state35&quot;],
["state4&quot;],
["state51&quot;,"state52&quot;,"state53&quot;,"state54&quot;,"state55&quot;]
]
property int counter:0
Timer {id:zen
interval: 2000; running: true; repeat: true
onTriggered: {
if(counter&lt;5)
branch=statesParameters[counter][0];
else
Qt.quit();
if(branch==false)
{
innerCounter=0;
top1.state=stateNames[counter][innerCounter];
counter=counter+1;
currentIndex=counter;
}
else
{
if(innerCounter&lt;statesParameters[counter][1])
{
top1.state=stateNames[counter][innerCounter];
innerCounter=innerCounter+1;
}
else{
counter=currentIndex+1;
if(counter&gt;=5) Qt.quit();
}
}
}//end of onTriggered
}// end of Timer
states:[
State {
name:"state11&quot;
PropertyChanges {target:top1;color:"Snow&quot;}
StateChangeScript {
name:"stateScript11&quot;
script:{
literal.text="Cupressaceae - State 11&quot;
picture.source=imagesList[0][2]
}
}
},
State {
name:"state12&quot;
PropertyChanges {target:top1;color:"Azure&quot;}
StateChangeScript {
name:"stateScript12&quot;
script:{
literal.text="Cupressaceae - State 12&quot;
picture.source=imagesList[0][0]
}
}
},
. . .

State {
name:"state55&quot;
PropertyChanges {target:top1;color:"PeachPuff&quot;}
StateChangeScript {
name:"stateScript55&quot;
script:{
literal.text="Roses - State55&quot;
picture.source="roses/katerach.jpg&quot;
}
}
}
]
}//end of top1

A Timer element is used to initiate the transition from the current state to the next one. Each state is represented visually by different images. The actions performed for each state are included in a StateChangesScript element block. There are three types of actions – changing the color of the frame containing the images, changing the images and altering the explanatory text in the upper text box.

The states are visited one by one. You may change the Timer interval property to control the rate of images rendering. The transition is implemented changing the property state of QML state "model&quot;:http://doc.qt.io/qt-4.8/qdeclarativestates.html.