Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to switch to another state at the end of a transition in QML?

Tags:

qt

qml

I'm trying to implement a fitness application that displays the current exercise name then shows a progress bar during the resting periods. When the progress bar is fully filled, the name of the next exercise is displayed, then a progress bar is shown when it is completed, and so on.

Note that I'm using a progress bar for this example but I'll have my own widget in the real application.

My system has two states :

  • exercise the value of the progress bar is 0 and stays 0
  • rest the value of the progress bar goes from 0 to maximumValue over the duration of the resting period

So it goes like this :

  1. the application is in "exercise" state and shows the name of the current exercicse
  2. the user execute the exercise and click on the progress bar when he's done
  3. the application switches to the "rest" state
  4. the user rests while the progress bar is being completed
  5. after the progress bar is completed the application switches back to the "exercise" state and displays the name of the next exercise

My issue is with step 5 : I do not know how to switch back to another state at the end of a transition. I've tried to change the "state" property during a PropertyChanges and time it at the end of a transition with a SequentialAnimation, but I get this error message :

QML StateGroup: Can't apply a state change as part of a state definition.

Here is some sample code :

import QtQuick 2.0
import QtQuick.Controls 1.1

ProgressBar {
    id: root

    width: 200
    height: 48

    minimumValue: 0
    maximumValue: 100
    value: 76

    function switchState() {
        if (state == "exercise")
        {
            state = "rest"
            return
        }

        if (state == "rest")
        {
            state = "exercise"
            return
        }
    }

    state: "exercise"

    states: [
        State {
            name: "exercise"
            PropertyChanges {
                target: root
                value: 0
            }
        },
        State {
            name: "rest"
            PropertyChanges {
                target: root
                value: maximumValue

                // error: QML StateGroup: Can't apply a state change as part of a state definition.
                // state: "exercise"
            }
        }
    ]

    transitions: [
        Transition {
            to: "rest"
            PropertyAnimation {
                target: root
                properties: "value"
                duration: 1000
            }
        }
    ]

    MouseArea {
        anchors.fill: parent
        onClicked: parent.switchState()
    }
}

How can I switch to another state at the end of a state transition ?

like image 717
Charles Avatar asked Apr 07 '14 02:04

Charles


2 Answers

I believe you can do this by using the RunningChanged signal from the transition:

transitions: [
    Transition {
        to: "rest"
        PropertyAnimation {
            target: root
            properties: "value"
            duration: 1000
        }

        onRunningChanged: {
            if ((state == "rest") && (!running))
                switchState();
        }
    }
]

QML Objects have an associated signal for property changes (on<Property>Changed). The associated handlers are usually not documented in the objects' references, but are implicitly available due to the property's existence. See this.

like image 61
GabrielF Avatar answered Oct 17 '22 18:10

GabrielF


UPDATE
I proposed a wrong solution because a mistake, so excuse me please.
Fixing its problem results same solution as @GabrielF one. So I deleted it to avoid repeating.

However below solution works great and gives you fine control within a Transition/Animaiton.

Also another way!

transitions: [
    Transition {
        to: "rest"
        SequentialAnimation {
            PropertyAnimation {
                target: root
                properties: "value"
                duration: 1000
            }
            ScriptAction { script: switchState() }    //<----
        }
    }
]    

Please note that with SequentialAnimation within a transition animation, you don't need to define a middle state, if you like to just ensure that an specific animation is completed.

Goodluck - S.M.Mousavi

like image 22
S.M.Mousavi Avatar answered Oct 17 '22 17:10

S.M.Mousavi