Traditional GUI programming often involves easy-to-write but boilerplate state machines for controls to track control and application states. For example, a button might have several states: when the mouse hovers over it, when it's pressed, and then once pressed, a separate state for on or off in the case of a checkbox or a push button. While this code isn't hard to write, it does involve some writing, and more sophisticated interfaces require more of it.
Qt Quick provides an abstraction for this through its State
construct, which groups a state's name as well as the condition under which it occurs, and which properties of an object should take on new values. We first saw this in Chapter 3, Designing Your Application with Qt Designer, when we wrote our own button component, reprinted here:
import QtQuick 2.3 Rectangle { id: button width: 64 height: 64 property alias operation: buttonText.text signal clicked color: "green" Rectangle { id: shade anchors.fill: button; color: "black"; opacity: 0 } Text { id: buttonText anchors.centerIn: parent; color: "white" font.pointSize: 16 } MouseArea { id: mouseArea anchors.fill: parent onClicked: { button.clicked(); } } states: State { name: "pressed"; when: mouseArea.pressed == true PropertyChanges { target: shade; opacity: .4 } } }
Here, the button has two states: the default state in which the shade is fully transparent, and when the user is pressing the button—represented by the pressed state—setting the shade's opacity
property to 0.4
. The states
field of an item can actually be an array; another way to write these states is to declare both explicitly, shown as follows:
states: [ State { name: "pressed"; when: mouseArea.pressed == true PropertyChanges { target: shade; opacity: .4 } }, State { name: "released"; when: mouseArea.pressed != true PropertyChanges { target: shade; opacity: 0.0 } } ]
Each State
construct can have more than one PropertyChanges
element, each with its own target and property, so you can create sophisticated state transitions using simple declarations.
Qt Quick uses transitions to control the animation of a property when a state change occurs. To create a transition, define an animation; you can apply an animation on any property that can be changed, specifying the start and end values of the animation. Consider a simple animation on a mouse press such as the following:
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true height: 360 width: 360 Rectangle { id: rect1 width: 100; height: 100 color: "red" MouseArea { id: mouseArea anchors.fill: parent } states: State { name: "moved"; when: mouseArea.pressed PropertyChanges { target: rect1; x: 100; y: 100 } } transitions: Transition { NumberAnimation { properties: "x,y" easing.type: Easing.InOutQuad } } } }
Here, the rectangle starts at the origin of the parent coordinate system, with MouseArea
in the rectangle. When you press the mouse in the rectangle, the state of the rectangle changes to moved, and the rectangle's top-left corner moves to (100,100) on the parent's canvas. However, we also specify an animation, NumberAnimation
, on the x
and y
properties, so the property change is animated to this value, with the easing curve we specify (a quadratic curve at both the start and finish of the animation).
NumberAnimation
to animate numeric properties, as you see hereColorAnimation
, which animates colors, and RotationAnimation
, which animates rotationsHere's the QML to rotate a red rectangle in a half-circle when it's clicked on:
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true height: 360 width: 360 Item { width: 300; height: 300 Rectangle { id: rect width: 150; height: 100; anchors.centerIn: parent color: "red" antialiasing: true states: State { name: "rotated" PropertyChanges { target: rect; rotation: 180 } } transitions: Transition { RotationAnimation { duration: 1000 direction: RotationAnimation.Counterclockwise } } } MouseArea { anchors.fill: parent; onClicked: rect.state = "rotated" } } }
Again, the pattern is the same: we define a state with PropertyChanges
, indicating the new property value, and then specify a transition over this property using an animation (in this case, RotationAnimation
). Here, the transition has a duration specified in milliseconds. Note that the rotation only occurs once, and the rotation angles are bound by the values -360 and 360 degrees.
For more information on the animation and transition framework in Qt Quick, see the Qt Quick documentation at http://qt-project.org/doc/qt-5/qtquick-statesanimations-animations.html and the Qt Quick Animation samples at http://qt-project.org/doc/qt-5/qtquick-animation-example.html.