Catch QML Component status/progress change signals - qt

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

Related

QtQuickControls FileDialog Automation

I'm trying to automate picking a file in QML in a QtQuick Controls FileDialog. How can I invoke FileDialog's accept with a specific fileUrl when the fileUrl property is read only?
The current attempt involves calling filedialog.clearSelection, filedialog.addSelection and finally filedialog.accept. clearSelection and addSelection are not documented but can be found in https://github.com/qt/qtquickcontrols/blob/dev/src/dialogs/qquickfiledialog.cpp (Assuming Qt has used a DefaultFileDialog as this can be system dependent)
However clearSelection seems to only work sporadically, having no affect if the same FileDialog has been used manually, hence the addSelection fails to set fileUrl.
The following is a QML file (loaded as a basic project within QtCreator) demonstrates this. with a manual file dialog open button and an automatic one:
import QtQuick 2.9
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.4
import QtQuick.Dialogs 1.3
Window {
visible: true;width: 200;height:200
FileDialog {id: filedialog; onAccepted: console.log("File Dialog Accepted: ", fileUrl, fileUrls);}
Row {
Button {text: "manual"; onClicked: filedialog.open()}
Button {
text: "auto_qml"
onClicked: {
console.log("Current selection:", filedialog.fileUrl, filedialog.fileUrls)
filedialog.clearSelection();
console.log("cleared selection:", filedialog.fileUrl, filedialog.fileUrls) // only clears selection if manual not used
let t = filedialog.addSelection("file:/home/user/tempfile.txt");
console.log("add selection success:", t) // a non existent file returns false, so file must exist
filedialog.accept()
}
}
}
}
As variant you can use Qt.labs.platform 1.1 library. It contains FileDialog with a little bit another behavior - file property is not read-only.
And you can do like so:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.4
import Qt.labs.platform 1.1
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
FileDialog {id: filedialog; onAccepted: console.log("File Dialog Accepted: ", file, files);}
Row {
Button {text: "manual"; onClicked: filedialog.open()}
Button {
text: "auto_qml"
onClicked: {
filedialog.file = "file:/home/user/tempfile.txt";
console.log("Current selection:", filedialog.file, filedialog.files)
filedialog.accepted()
}
}
}
}

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?

Show message dialog

Is it possible to display a QML dialog when the user hits a button in a QML window?
Example:
When the user clicks in the menu bar on Help -> About the About dialog should be displayed:
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import "components"
ApplicationWindow {
id: window
visible: true
width: 1040
height: 480
aboutDlg: aboutDialog {} // does not work...
menuBar: MenuBar {
Menu {
title: qsTr("Help")
MenuItem {
text: qsTr("About")
onTriggered: aboutDlg.open();
}
}
...
components/AboutDialog.qml
import QtQuick 2.2
import QtQuick.Dialogs 1.1
MessageDialog {
id: aboutDialog
title: "May I have your attention please"
text: "It's so cool that you are using Qt Quick."
onAccepted: {
console.log("And of course you could only agree.")
Qt.quit()
}
}
When I remove the line boutDlg: aboutDialog {} // does not work... the following error is reported when clicking on the About menu item:
qrc:/main.qml:61: ReferenceError: aboutDlg is not defined
How can I achieve this?
You called "aboutDialog" which is an ID in the AboutDialog.
Think of it like you add an object, like adding a Rectangle...which has its own file...and you can "instantiate" it by adding an object like so:
...
ApplicationWindow {
...
AboutDialog {
id: aboutDlg
}
...
}
You can find example HERE
You might also optimize a bit and put the AboutDialog in a Loader.

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

Interaction between two QML files

I want to use some qml file(main.qml) but before that I need to get some authentication info from user(login, pass). So I want to do this in the second window(login.qml). I saw Qt.createComponent for opening second qml file, but I can't get any information from this type of window.
So how can I use some information from the second window in the first window?
Or how can I dynamically load these items(main.qml, login.qml) in the parent qml file?
So how can I use some information from the second window in the first
window?
This is just one way of doing it:
main.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
ApplicationWindow {
width: 400
height: 400
visible: true
ColumnLayout {
id: logItems
height: 200
Button {
id: loginButton
onClicked: loginForm.visible = true
text: "Log in"
}
Login {
anchors.top: loginButton.bottom
id: loginForm
visible: false
onLoginInfo: {
logInfo.text = "User:" + user + " password: " + password
}
}
}
Text {
id: logInfo
anchors.top : logItems.bottom
}
}
Login.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
Item {
signal loginInfo(string user, string password)
ColumnLayout {
RowLayout {
TextField {
id: user
}
TextField {
id: password
}
}
Button {
text: "Submit"
onClicked: loginInfo(user.text, password.text)
}
}
}
How can I dynamically load QML items from separate files/resources in
another QML file?
Qt.CreateComponent allows you to use JavaScript to dynamically create and use QML code from other files.

Resources