evadeflow
evadeflow

Reputation: 4944

How to run QML StateMachine example from Qt's documentation?

I'm getting back into Qt lately after a hiatus of several years, and it looks like QML is the "new hotness" these days. In the past, I've managed to get widget-based examples from Qt's documentation to work with relative ease, but... now that I'm trying to learn QML, I'm having trouble closing the gaps in the example code.

Specifically, the docs for Qt.QmlStateMachine say:

The following snippet shows a state machine that will finish when a button is clicked:

import QtQuick 2.0
import QtQml.StateMachine 1.0 as DSM

Rectangle {
    Button {
        anchors.fill: parent
        id: button
        text: "Finish state"
        DSM.StateMachine {
            id: stateMachine
            initialState: state
            running: true
            DSM.State {
                id: state
                DSM.SignalTransition {
                    targetState: finalState
                    signal: button.clicked
                }
            }
            DSM.FinalState {
                id: finalState
            }
            onFinished: Qt.quit()
        }
    }
}

Perhaps I'm completely naive, but I thought I could just create a new Qt Quick application in QtCreator and paste the above snippet into main.qml. When I do this, though, I'm immediately confronted with an error saying:

QQmlApplicationEngine failed to load component
qrc:/main.qml:19 Button is not a type

So... I look at the docs for the QML Button type and notice that it says near the top:

Import Statement: import QtQuick.Controls 1.4

So, I add that to the top of main.qml and try to run again. And it 'works', but... there's no main window—or any other visual content whatsoever. Hmm. I guess I can see where that (maybe) makes sense, perhaps I shouldn't have replaced the entire contents of main.qml? So I decide to try retaining the Window component from the original QML supplied by QtCreator, changing my main.qml file to look like this:

import QtQuick 2.8                                                                                                                                                                                                                                            
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQml.StateMachine 1.0 as DSM

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        Button {
            anchors.fill: parent
            id: button
            text: "Finish state"
            DSM.StateMachine {
                id: stateMachine
                initialState: state
                running: true
                DSM.State {
                    id: state1
                    DSM.SignalTransition {
                        targetState: finalState
                        signal: button.clicked
                    }
                }
                DSM.FinalState {
                    id: finalState
                }
                onFinished: Qt.quit()
            }
        }
    }
}

After doing this, I see a main window when I run, but it is empty. Um... shouldn't there at least be a button in there somewhere?

Anyway, I wasn't smart enough to figure this out after almost 90 minutes of fiddling around. It seems that Qt's documentation authors are assuming a basic level of QML knowledge that I simply don't possess, so I'm unable to 'fill in the blanks'. Which is a real shame, because QML looks awesome. And I'm particularly excited to see what I can do with the declarative state machine framework! Can anybody tell me what I'm doing wrong with this particular example?

(In case it matters, I'm using Qt 5.9.2 with QtCreator 4.4.1...)

UPDATE: In his answer, @eyllanesc pointed out a small typo in the second code snippet I posted above. Where I wrote id: state1, it should have been id: state.

Upvotes: 0

Views: 1621

Answers (1)

eyllanesc
eyllanesc

Reputation: 243983

The documentation assumes some basic knowledge of the previous topics and in the initial paragraph: http://doc.qt.io/qt-5/qtqml-index.html gives you a list of topics that you should read and learn.

And like all language one must read the errors of the code and analyze its logic.

...main.qml:17:13: QML StateMachine: No initial state set for StateMachine
QStateMachine::start: No initial state set for machine. Refusing to start.
.../main.qml:19: ReferenceError: state is not defined

This error clearly indicates that the initial state is not recognized, and this can be caused by 2 reasons, the first is that you have not established it or the second is that you have established an inappropriate state, and in your case it is the second reason.

you have established the initial state:

initialState: state

but state does not exist, I think you wanted to place state1

initialState: state1

The button is not shown because you have established that its size is the same as that of the parent: anchors.fill: parent, and Button's parent is Rectangle, and if Rectangle is not set a size will have a size of 0, causing the son to have it too. A possible solution is to establish Rectangle the size of the parent:

import QtQuick 2.8                                                                                                                                                                                                                                            
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQml.StateMachine 1.0 as DSM

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        anchors.fill: parent
        Button {
            anchors.fill: parent
            id: button
            text: "Finish state"
            DSM.StateMachine {
                id: stateMachine
                initialState: state1
                running: true
                DSM.State {
                    id: state1
                    DSM.SignalTransition {
                        targetState: finalState
                        signal: button.clicked
                    }
                }
                DSM.FinalState {
                    id: finalState
                }
                onFinished: Qt.quit()
            }
        }
    }
}

or not use Rectangle:

import QtQuick 2.8                                                                                                                                                                                                                                            
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQml.StateMachine 1.0 as DSM

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Button {
        anchors.fill: parent
        id: button
        text: "Finish state"
        DSM.StateMachine {
            id: stateMachine
            initialState: state1
            running: true
            DSM.State {
                id: state1
                DSM.SignalTransition {
                    targetState: finalState
                    signal: button.clicked
                }
            }
            DSM.FinalState {
                id: finalState
            }
            onFinished: Qt.quit()
        }
    }
}

Upvotes: 1

Related Questions