Skip to content
nucularmoo edited this page Apr 14, 2018 · 7 revisions

State Machines (P1 | 2h)

Explanation of the contents of a topic page @ Week 1 Topic 1

Back to Week 2

Objective: Fluid UI with state machines and animations

Comment: Added with state machines and animations to the objective

Beginner

  • What is a state machine?

Intermediate

  • What does "state machine" mean in this context?
  • How do "state machines" relate to fluid UI?
  • What is a property change?
  • How do you define state transitions?
  • How do you animate state transitions?

Expert

Omitted


Course material content

http://doc.qt.io/qt-5/qml-qtquick-state.html#details http://doc.qt.io/qt-5/qtquick-statesanimations-states.html

States

A state is a set of batched changes from the default configuration.

All items have a default state that defines the default configuration of objects and property values. New states can be defined by adding State items to the states property to allow items to switch between different configurations. These configurations can, for example, be used to apply different sets of property values or execute different scripts.

The following example displays a single Rectangle. In the default state, the rectangle is colored black. In the "clicked" state, a PropertyChanges object changes the rectangle's color to red. Clicking within the MouseArea toggles the rectangle's state between the default state and the "clicked" state, thus toggling the color of the rectangle between black and red.

 import QtQuick 2.0

 Rectangle {
      id: myRect
      width: 100; height: 100
      color: "black"

      MouseArea {
          id: mouseArea
          anchors.fill: parent
          onClicked: myRect.state == 'clicked' ? myRect.state = "" : myRect.state = 'clicked';
      }

      states: [
           State {
                name: "clicked"
                PropertyChanges { target: myRect; color: "red" }
           }
      ]
 }

Notice the default state is referred to using an empty string ("").

States are commonly used together with Transitions to provide animations when state changes occur.

Note: Setting the state of an object from within another state of the same object is not allowed.

Creating states

To create a state, add a State object to the item's states property, which holds a list of states for that item.

A warning signal component may have two states, the NORMAL and the CRITICAL state. Suppose that in the NORMAL state, the color of the signal should be green and the warning flag is down. Meanwhile, in the CRITICAL state, the color should be red and the flag is up. We may model the states using the State type and the color and flag configurations with the PropertyChanges type.

 Rectangle {
      id: signal
      width: 200; height: 200
      state: "NORMAL"

      states: [
           State {
                name: "NORMAL"
                PropertyChanges { target: signal; color: "green"}
                PropertyChanges { target: flag; state: "FLAG_DOWN"}
           },
           State {
                name: "CRITICAL"
                PropertyChanges { target: signal; color: "red"}
                PropertyChanges { target: flag; state: "FLAG_UP"}
           }
      ]
 }

The PropertyChanges type will change the values of object properties. Objects are referenced through their id. Objects outside the component are also referenced using the id property, exemplified by the property change to the external flag object.

Further, the state may change by assigning the state property with the appropriate signal state. A state switch could be in a MouseArea type, assigning a different state whenever the signal receives a mouse click.

 Rectangle {
      id: signalswitch
      width: 75; height: 75
      color: "blue"

      MouseArea {
           anchors.fill: parent
           onClicked: {
                if (signal.state == "NORMAL")
                     signal.state = "CRITICAL"
                else
                     signal.state = "NORMAL"
           }
      }
 }

The State type is not limited to performing modifications on property values. It can also:

  • Run some script using StateChangeScript
  • Override an existing signal handler for an object using PropertyChanges
  • Re-parent an Item using ParentChange
  • Modify anchor values using AnchorChanges

The Default State

Every Item based component has a state property and a default state. The default state is the empty string ("") and contains all of an item's initial property values. The default state is useful for managing property values before state changes. Setting the state property to an empty string will load the default state.

The when Property

For convenience, the State type has a when property that can bind to expressions to change the state whenever the bound expression evaluates to true. The when property will revert the state back to the default state when the expression evaluates to false.

 Rectangle {
      id: bell
      width: 75; height: 75
      color: "yellow"

      states: State {
                   name: "RINGING"
                   when: (signal.state == "CRITICAL")
                   PropertyChanges {target: speaker; play: "RING!"}
              }
 }

The bell component will change to the RINGING state whenever the signal.state is CRITICAL.

Animating State Changes

State changes induce abrupt value changes. The Transition type allow smoother changes during state changes. In transitions, animations and interpolation behaviors are definable. The Animation and Transitions article has more information about creating state animations.

The States and Transitions example demonstrates how to declare a basic set of states and apply animated transitions between them.

Using Qt Quick Behaviors with States explains a common problem when using Behaviors to animate state changes.

Transitions

http://doc.qt.io/qt-5/qml-qtquick-transition.html#details http://doc.qt.io/qt-5/qtquick-animation-example.html#transitions

Transitions takes the States example and animates the property changes by setting transitions:

 // Transitions define how the properties change when the item moves between each state
 transitions: [

      // When transitioning to 'middleRight' move x,y over a duration of 1 second,
      // with OutBounce easing function.
      Transition {
           from: "*"; to: "middleRight"
           NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce; duration: 1000 }
      },

      // When transitioning to 'bottomLeft' move x,y over a duration of 2 seconds,
      // with InOutQuad easing function.
      Transition {
           from: "*"; to: "bottomLeft"
           NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad; duration: 2000 }
      },

      // For any other state changes move x,y linearly over duration of 200ms.
      Transition {
           NumberAnimation { properties: "x,y"; duration: 200 }

A Transition defines the animations to be applied when a State change occurs.

For example, the following Rectangle has two states: the default state, and an added "moved" state. In the "moved state, the rectangle's position changes to (50, 50). The added Transition specifies that when the rectangle changes between the default and the "moved" state, any changes to the x and y properties should be animated, using an Easing.InOutQuad.

 import QtQuick 2.0

 Rectangle {
      id: rect
      width: 100; height: 100
      color: "red"

      MouseArea {
          id: mouseArea
          anchors.fill: parent
      }

      states: State {
           name: "moved"; when: mouseArea.pressed
           PropertyChanges { target: rect; x: 50; y: 50 }
      }

      transitions: Transition {
           NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad }
      }
 }

Notice the example does not require to and from values for the NumberAnimation. As a convenience, these properties are automatically set to the values of x and y before and after the state change; the from values are provided by the current values of x and y, and the to values are provided by the PropertyChanges object. If you wish, you can provide to and from values anyway to override the default values.

By default, a Transition's animations are applied for any state change in the parent item. The Transition from and to values can be set to restrict the animations to only be applied when changing from one particular state to another.

To define multiple transitions, specify Item::transitions as a list:

 transitions: [
    Transition {
         from: "stop"; to: "go"
         PropertyAnimation { target: stopLight
                             properties: "color"; duration: 1000 }
    },
    Transition {
         from: "go"; to: "stop"
         PropertyAnimation { target: goLight
                             properties: "color"; duration: 1000 }
     } ]

If multiple Transitions are specified, only a single (best-matching) Transition will be applied for any particular state change. In the example above, when changing to state1, the first transition will be used, rather than the more generic second transition.

If a state change has a Transition that matches the same property as a Behavior, the Transition animation overrides the Behavior for that state change.

Instructions and description for the exercise of the topic


Exhaustive reference material mentioned in this topic

Further reading topics/links:

Clone this wiki locally