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

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.

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()
}
}
}

Related

Keys.onPressed stops working when i focus else but then back to original item

im facing something which I cant explain...
I have this code:
import QtQuick 2.12
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.12
import QtQuick.LocalStorage 2.0
import QtMultimedia 5.15
import 'JavaScript.js' as JS
ApplicationWindow {
id: mainWindow
visible: true
width: 480 height: 800
title: qsTr("application")
Item {
id: keyboardHandler
focus: true
onFocusChanged: console.log(keyboardHandler.focus);
Keys.onPressed: { console.log(event.text; }
}
Image {
id: focusToKeyboardHandler
anchors.fill: parent
MouseArea {
anchors.fill: parent
onClicked: { keyboardHandler.focus = true; }
}
}
TextField {
id: textfieldID
}
}
and when I start the application, then all keyboard strokes properly prints into console as they should...
however if i click into the TextField, then back to image, then the keystrokes dont print anything at all :(
Why? when I click on the Image, the it properly givers me focus to keyboardHandler (proved by onFocusChanged always debugs true before i start typing... so focus on keyboardHandler is always there when needed)...
Just to be sure I have also tried to change this row to:
onClicked: { keyboardHandler.focus = true; keyboardHandler.forceActiveFocus(); }
with no luck
UPDATE: it works on physical typing onto keyboard keys... however using the barcode scanner which is HID it works only first time i start the application, not when i change focus and then back to keyboardHandler
UPDATE2: when turning application off and on works again only for the first time (or till i rechange the focus)
any ideas what could cause this?

OnClicked property sends data back to Go, but slot isn't invoked

So, I am trying to write a simple login page in Qml, the user writes data in the two text fields, and once the login button is pressed the Go Slot will send some data over to another function for authentication.
The only problem is, when the login button is pressed, the slot isn't invoked, the code continues outside the main loop that creates the UI and exits the program with a SIGSEV.
Basically going past:
// Execute app
gui.QGuiApplication_Exec()
and exiting MakeUI()
With this error:
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0x265a014]
Here's my Go Code:
package UI
import (
"fmt"
_ "github.com/heyuan110/gorepertory/logger"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui"
"github.com/therecipe/qt/qml"
"github.com/therecipe/qt/quickcontrols2"
"os"
)
type QmlBridge struct {
core.QObject
//_ func(username string,password string) bool `signal:sendToQml`
_ func(username string,password string )bool `slot:sendToGo`
}
func MakeUI() {
//var QmlBridgeVar *QmlBridge
var QmlBridgeVar = NewQmlBridge(nil)
// Create application
app := gui.NewQGuiApplication(len(os.Args), os.Args)
// Enable high DPI scaling
app.SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
// Use the material style for qml
quickcontrols2.QQuickStyle_SetStyle("material")
// Create a QML application engine
engine := qml.NewQQmlApplicationEngine(nil)
engine.RootContext().SetContextProperty("QmlBridgeVar", QmlBridgeVar)
//QmlBridgeVar.ConnectSendToQml(func(username string,password string){
//
//})
QmlBridgeVar.ConnectSendToGo(func(username string, password string){
fmt.Println(username,password)
})
// Load the main qml file
engine.Load(core.NewQUrl3("qml/main.qml", 0))
// Execute app
gui.QGuiApplication_Exec()
}
And here's my Corresponding Qml:
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
title: "Bouncer"
property int margin: 11
minimumWidth: 600
minimumHeight: 450
ColumnLayout {
id: mainLayout
anchors.fill: parent
anchors.margins: margin
GroupBox {
id: rowBox
title: "Login"
Layout.fillWidth: true
RowLayout {
id: rowLayout
anchors.fill: parent
TextField {
id: usernameField
placeholderText: "Username"
Layout.fillWidth: true
}
TextField {
id: passwrdField
placeholderText: "Password"
Layout.fillWidth: true
}
Button {
id: loginButton
text: "Login"
MouseArea{
id: loginMouseArea
anchors.fill: parent
onClicked: QmlBridgeVar.sendToGo(usernameField.text, passwrdField.text)
}
}
}
}
}
}
I am prone to believe I might have some problems with the Qt bindings for go? Though I am not entirely sure. If anybody can give me valuable feedback I'd highly appreciate it.

Catch QML Component status/progress change signals

I'm trying to debug my QML application which is experiencing freezes at load. I'm not getting Component.onCompleted signals from any of my components, so I'm trying to check the Component.status changes, however QML is throwing a Cannot assign to non-existent property "onStatusChanged" warning when I try with the following example. How can I get notified of status or progress changes on components?
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import QtWebEngine 1.10
import QtWebChannel 1.0
ApplicationWindow {
width: 600
height: 480
visible: true
WebEngineView {
anchors.fill: parent
url: "https://www.xkcd.com"
}
Component.onCompleted: print("Completed")
Component.onStatusChanged: print("Status changed: ", status)
Component.onProgressChanged: print("Progress changed: ", progress)
}
You can't access Component properties, like status from there. You can only access the onCompleted signal because it's an "attached signal". I would use a Loader to track progress. Try it like this:
Loader {
asynchronous: true
sourceComponent: WebEngineView {
anchors.fill: parent
url: "https://www.xkcd.com"
}
onProgressChanged: {
console.log("progress: " + progress)
}
}

Qt - QQuickView(), setSource without freezing the GUI

being trying to solve issue for a long time, no success, QT version 5.15.0. MinGW 8.1.0, 64 bit
The issue seems to happen only when loading the map plugin in the QML file, below is a snip it of the code
The call qmlView->setSource(QUrl("qrc:/maps/map.qml")); waits at least 2 seconds and the GUI then freeze. Basically the GUI thread is blocked for 2 seconds.
I tried to call qmlView->setSource(QUrl("qrc:/maps/map.qml")) in a separate thread but crashed,
Not too sure if the Loader QML Type would work, becasue its the same GUI thread.
I even tried the example for https://doc.qt.io/qt-5/qtlocation-mapviewer-example.html, when you change provider the main GUI also freezes
Is there any way to load the QML files where the GUI does not freeze?
Thanks
QQuickView * qmlView = new QQuickView();
QQmlEngine * eng = qmlView->engine();
eng->addPluginPath(qApp->applicationDirPath());
qmlView->setSource(QUrl("qrc:/maps/map.qml"));
The QML file is
import QtQuick 2.0
import QtQuick.Window 2.0
import QtLocation 5.15
import QtPositioning 5.6
Item {
id: item
anchors.fill: parent
visible: true
Plugin {
id: mapPlugin
name: "osm" // Other mapas are "osm", "mapbox" "mapboxgl", "esri", ...
}
Map {
id: map
anchors.fill: parent
anchors.leftMargin: -84
anchors.topMargin: -47
objectName: "rect"
plugin: mapPlugin
center {
latitude: 52.1619403
longitude: -7.1488692
}
zoomLevel: 14
}
}
After the input from JarMan, I tried to use the QML Loader, see below, but the GUI still freezes
Loader {
id: windowLoader
source: "qrc:/maps/map.qml"
focus: true
asynchronous: true
//property bool valid: item !== null
}

How to use QML Connect{} with Qt Creator Design Mode

The below code works fine in Qt Creator Edit Mode, but when I try to switch to Design Mode it gives an error:
"Can not open this qml document because of an error in the qml file."
And then I can't edit the layout graphically. If I comment out the Connect{} item then Design Mode works again and I can edit graphically.
Anybody see what the error might be.
What am I doin wrong? Thanks for looking.
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: window1
visible: true
Rectangle {
id: rect
color: "#ffffff"
width: 100; height: 100
MouseArea {
id: mouseArea
anchors.fill: parent
}
Connections {
target: mouseArea
onClicked: {
print("clicked")
}
}
}
}

Resources