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

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?

Related

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

QML progress bar is NOT showing up on UI

I have this QML progress bar:
import QtQuick.Controls 2.0 as QQC20
Item {
QQC20.ProgressBar {
id: progressbar_id
visible: false // even if "true", the progress bar does NOT show up on UI
from: editorScene.progressbarMin
to: editorScene.progressbarMax
value: editorScene.progressbarVal
onValueChanged: {
console.log("Progressbar value changed: ", progressbar_id.value)
}
onVisibleChanged: {
console.log("Progressbar visibility chanaged: ", progressbar_id.visible)
}
}
}
I can confirm that the progress bar value and visibility are changed by the methods onValueChanged and onVisibleChanged.
However, the problem is that the progress bar does NOT show up on the UI! How can I actually show the progress bar on the UI? Can anybody give me a hint?
Right now, all you're doing is creating a QML type which you can use as part of your API. To actually see it, you need to create an instance of it under a ApplicationWindow or Window (or anything else equivalent, e.g. Canvas or Felgo's GameWindow).
There are two ways you can accomplish this. You can
Directly add your item as a child of a window.
Put your item in a separate file, and create an instance of that file under a window.
Lé Code
Method 1: Directly Adding as Child
Directly insert your codeblock as a child of an ApplicationWindow.
// Main.qml
import QtQuick 2.0 // for `Item`
import QtQuick.Window 2.0 // for `ApplicationWindow`
import QtQuick.Controls 2.0 // as QQC20 // no need to label a namespace unless disambiguation is necessary
ApplicationWindow {
width: 480 // set the dimensions of the application window
height: 320
// here's your item
Item {
anchors.centerIn: parent // place in centre of window
ProgressBar {
id: progressbar_id
anchors.horizontalCenter: parent.horizontalCenter // horizontally align the progress bar
from: 0 // don't know what editorScene is
to: 100 // so I'm using raw values
value: 5
onValueChanged: {
console.log("Progressbar value changed: ", progressbar_id.value)
}
onVisibleChanged: {
// side note: I'm not getting any output from this handler
console.log("Progressbar visibility chanaged: ", progressbar_id.visible)
}
}
}
// provide user-interaction for changing progress bar's value
MouseArea {
anchors.fill: parent // clicking anywhere on the background
onClicked: progressbar_id.value += 5; // increments the progress bar
// and triggers onValueChanged
}
}
Method 2: Using a Separate File
Save your item into a new qml file.
// MyProgressBar.qml
import QtQuick 2.0 // for `Item`
import QtQuick.Controls 2.0 // for `ProgressBar`
// here is your item, it has grown up to be in a file of its own 🚼
Item {
property alias value: progressbar_id.value // for user-interaction
ProgressBar {
id: progressbar_id
anchors.horizontalCenter: parent.horizontalCenter // centre horizontally
from: 0
to: 100
value: 5
onValueChanged: {
console.log("Progressbar value changed: ", progressbar_id.value)
}
onVisibleChanged: {
console.log("Progressbar visibility chanaged: ", progressbar_id.visible)
}
}
}
Note that you still need the import statements.
Then call it from a window in Main.qml. We'll use an ApplicationWindow here.
// Main.qml
import QtQuick 2.0
import QtQuick.Window 2.0 // for `ApplicationWindow`
// import "relative/path/to/progressbar" // use this if MyProgressBar.qml is not in the same folder as Main.qml
ApplicationWindow {
width: 480
height: 320
MyProgressBar {
id: progressbar_id
}
MouseArea {
anchors.fill: parent
onClicked: progressbar_id.value += 5;
}
}
If your qml files aren't in the same directory, make sure you add an import "relative/path" at the top of the Main.qml file among the other import statements.
For example, if
Your Qml project is in /Users/Lorem/Project,
The full path to your Main.qml is /Users/Lorem/Project/qml/Main.qml, and
The full path to your MyProgressBar.qml is /Users/Lorem/Project/qml/myControls/MyProgressBar.qml...
Then use import "myControls" in Main.qml to import the items from the myControls subdirectory. Remember, you only need to import the directory, not the file itself.
Result
This is what the result resembles when I run it from a macOS.
At startup.
After 3 clicks on the background.
There is also console/debug output after each click:
Progressbar value changed: 10
Progressbar value changed: 15
Progressbar value changed: 20

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

Disable mouse wheel for QML Slider

I want to be able to scroll Flickable with mouse wheel (or two fingers on touchpad) without changing Sliders it may containt.
Sample code and result application:
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: rootWindow
visible: true
width: 400
height: 200
title: qsTr("Hello World")
ScrollView {
anchors.fill: parent
flickableItem.flickableDirection: Flickable.VerticalFlick
Column {
Repeater {
model: 40
Slider {
width: rootWindow.width * 0.9
}
}
}
}
}
Looks like there was some attempt to fix this in the past, but not successful.
EDIT: this relates to Controls 1.x only, as controls doesn't seem to have this issue starting from 2.0 version.
You can place MouseAreas on the sliders to steal the mouse wheel event.
Something like this:
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: rootWindow
visible: true
width: 400
height: 200
title: qsTr("Hello World")
ScrollView {
id: _scrollview
anchors.fill: parent
flickableItem.flickableDirection: Flickable.VerticalFlick
Column {
Repeater {
model: 40
Slider {
width: rootWindow.width * 0.9
property int scrollValue: 10
MouseArea {
anchors.fill: parent
onWheel: {
//check if mouse is scrolling up or down
if (wheel.angleDelta.y<0){
//make sure not to scroll too far
if (!_scrollview.flickableItem.atYEnd)
_scrollview.flickableItem.contentY += scrollValue
}
else {
//make sure not to scroll too far
if (!_scrollview.flickableItem.atYBeginning)
_scrollview.flickableItem.contentY -= scrollValue
}
}
onPressed: {
// forward mouse event
mouse.accepted = false
}
onReleased: {
// forward mouse event
mouse.accepted = false
}
}
}
}
}
}
}
Using the onWheel - event to forward any scrolling to the ScrollView. The other mouse events, such as clicking, can be forwarded to the parents (in this case the sliders) by setting mouse.accepted = false; for any mouse event you wish to have forwarded.
Edit: Oh, I just saw now that you don't want any changes in the sliders contents. You can also to try to place a MouseArea all over the ScrollView and do the same forwarding.
The easiest, if feasible for you, would probably be, to change from QtQuick.Controls 1.4 which can be either considered deprecated, not maintained, or low-performing to the new QtQuick.Controls 2.0
In this version your issue has been adressed.
To adress your need of QtQuick.Controls 1.4 we'll import the QtQuick.Controls 2.0 with an alias:
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls 2.0 as NewCtrl
Column {
Slider {
id: oldslider // old slider from QtQuick.Controls 1.4 with your issue
width: 500
height: 250
}
NewCtrl.Slider {
id: newsli // new slider without your issue. Both side by side
width: 500
height: 30
wheelEnabled: false // use this to enable or disable the wheel
}
}
Of course you can also alias the old controls and use the new one as the basic... Or alias both. As you like
Hack from here did it for me.
Slider {
id: slider
Component.onCompleted: {
for (var i = 0; i < slider.children.length; ++i) {
if (slider.children[i].hasOwnProperty("onVerticalWheelMoved") && slider.children[i].hasOwnProperty("onHorizontalWheelMoved")) {
slider.children[i].destroy()
}
}
}
}
This may not work with other controls (e.g. ComboBox).

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