QML: Buttons of invisible screens still active? - qt

I am developing a qml application for a touchscreen. The app is organized into different screens
e.g. in my main.qml looks like this
ApplicationWindow {
visible: true
width: 1024
height: 600
Screen1 {
id: screen1
visible: true
}
Screen2 {
id: screen2
visible: false
}
I switch between these screens, through buttons, e.g. on Screen1 there would be a mouseArea which does
onClicked: {
screen1.visible=false
screen2.visible=true
}
I now wonder whether this is the way to do it, as I observe a strange behaviour: I have a button on screen2 which is at the same position as a button on screen1 (which triggers Qt.quit(). The button on screen2 most of the time does what it should. However, if I click several times on it, sometimes the quit button on screen1 is triggered (I explicitly checked with a log.console writeout), although this screen is invisible.
Why does this happen and how can I avoid this behaviour?

Related

QML BusyIndicator how to overlay the current window, like ProgressDialog in Android

Iam using QML Busyindicator when a user login or loading a data in a page or something like this, I want to be able to make the busyindicator overlay over the current window and make the window not editable, something similar to the messagebox when it shows up and disables all the Window, so I cant interact with the widgets on this window until the loading finish, something like the ProgressDialog in Android.
this is my code and what I try to do, also I tried to use MessageDialog and use this indicator inside it and remove all buttons, but it does not work.
Popup {
id: waitpop
width: 100
height: 100
BusyIndicator {
id: login_progress
running: true
anchors.fill: parent
}
anchors.centerIn: Overlay.overlay
closePolicy: Popup.NoAutoClose
}
this code shows the busy indicator but the user still can interact with the button and text field and everything, so any ideas?
The modal property prevents you from being able to click outside the popup.
Popup {
anchors.centerIn: Overlay.overlay
closePolicy: Popup.NoAutoClose
modal: true
BusyIndicator {
running: true
}
}

Why Qml Popup modality is ignored?

I have an issue with Popup (default qml class) not being modal, despite modality set to true and closePolicy to NoAutoClose.
The problem occurs when I open the Popup by clicking a standard qml button. After opening Popup, a lengthy operation is performed, then Popup is closed.
When operation is running, whole application and the Popup itself reacts to mouse clicks. But it doesn't close the Popup. Instead it somehow clicks the button, that opened the Popup again. That shouldn't happen since my Popup is modal.
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Controls 2.4
ApplicationWindow {
id: main_window
visible: true
width: 800
height: 500
Item {
anchors.fill: parent
Popup {
id: blockingPopup
width: 300
height: 50
modal: true
focus: true
closePolicy: Popup.NoAutoClose
}
Button {
text: "Btn"
onClicked: {
console.log("clicked")
blockingPopup.open();
cppModel.lengthyOperation()
blockingPopup.close();
}
}
}
}
To summarize it again: the button is somehow clicked when I click outside (or even inside) the modal Popup when it is displayed and the operation is running.
Qt 5.12.0, Linux Mint 19.2
Problem was in QCoreApplication::processEvents() that was in my cpp model function. It was causing clicks on a modal popup to be registered as clicks on button.

Popup in qml : (closePolicy: Popup.NoAutoClose)

When ever i am using closePolicy: Popup.NoAutoClose,
This popup is opened all the time and not getting closed (which is valid). When i am switching to some other screen, popup is opened and visible in other screens also.
How to avoid this kind of behaviour?
Note: I want popup to be visible specific to that particular screen where it is opened and not on other screens.
You can use Binding to control the popup's visibility based on the name of the screen it was opened in:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
width: 400
height: 400
visible: true
Popup {
id: popup
width: 200
height: 200
visible: true
closePolicy: Popup.NoAutoClose
property string originalScreenName
Component.onCompleted: originalScreenName = ApplicationWindow.window.screen.name
Binding {
target: popup
property: "visible"
value: popup.ApplicationWindow.window.screen.name === popup.originalScreenName
}
}
}
I don't know if the name property can change during the lifetime of the application (e.g. due to a user renaming it), but so far it's the only way I've found of uniquely identifying a screen, as the other properties like serialNumber are not set for me, and QTBUG-85934 prevents comparing screen objects.

Qt5-QML: How to handle change of color and text of a button after click event

I am writing a small application that is working as follows:
1) I launch the application and I select a robot to which I will connect. See print screen below of the small app:
2) That will lead me to another page where I can actually choose the robot to connect to as shown in the print screen below:
3) Finally after selecting the robot the application brings me back to the initial screen that will show me an additional Button showing the chosen robot.
The problem: I have is that after I choose the robot and I am back to the initial screen and I push the button the color of the button should turn into a (for example) green color and changing the text into (for example) Connecting...
The code I am using is the following for which I am only putting the related part:
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.Styles 1.4
Page {
property int dialogId: -1
signal selectDialog()
ColumnLayout {
anchors.fill: parent
spacing: 5
Button {
id: button1
text: "Select Robot"
onClicked: selectDialog()
Layout.fillWidth: true
font.pointSize: 20
}
Button {
id: dialogA
text: "FreddieMercury: Connect";
visible: dialogId === 1
Layout.fillWidth: true
font.pointSize: 20
function buttonClick()
{
console.log("Button "+ dialogA.text +" is clicked!")
}
Rectangle {
id: button
color: "red"
width: 96; height: 24; anchors.centerIn: parent
MouseArea {
id: region
anchors.fill: parent;
onClicked: console.log("clicked()")
onPressed: dialogA.color = "green"
onReleased: dialogA.color = "red"
}
Text {
id: st_text
anchors.centerIn: parent
text: "Connecting..."
font.bold: true
font.pointSize: 20
color: "green"
}
}
}
// Other Buttons
}
}
What I tried so far
I went through this source and also this post which I followed. As you can see from the point 3) I am close to the good functioning but there is clearly something I am not doing right.
Also this was useful and in fact I used the MouseArea option exactly from that post.
However I still don't see the whole color extended into the button.
Finally the text changed after the click event happened I included it in the Button as shown and thought that the property text: "Connecting..." was enough to overwrite the existing text but without success.
Please advise on what I am missing that is keeping me from a full working example.
I think the base issue is that you're trying to use examples for QtQuick Controls 1 with QtQuick Controls 2. They're completely different animals and you cannot style the v2 controls using QtQuick.Controls.Styles.
For customizing Controls 2 styles, like Button, see here. I also find it useful to look at the source code for the included controls (they're in your Qt library install folder inside /qml/QtQuick/Controls2/ directory). Though personally I find needing to re-create a whole new Button (or whatever) just to change a color or font is a bit much, especially if I want it to work across all the included QtQuick Controls2 Styles.
An alternative is to "hack" the properties of the built-in Control styles. This certainly has some drawbacks like if you want to be able to reset the control style back to default bindings, you'd have to save the original bindings and re-create them to reset the style. OTOH it beats creating customized controls for each style. YMMV.
Anyway here's an example of what i think you're looking for. This is based on our previous exercise with the buttons. :) Specifically, I just modified the Page1.qml code and the other 2 files are exactly the same as before. In this page I added buttonClick() handler and the Button::onClicked calls to trigger it from each button (and the button texts of course :).
Page1.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.impl 2.12 // for IconLabel
import QtQuick.Layouts 1.12
Page {
property int dialogId: -1;
signal selectDialog()
function buttonClick(button)
{
button.text = qsTr("Connecting to %1...").arg(button.text);
button.enabled = false; // prevent repeat clicks
// If Button has a background Rectangle object then we can set properties on it.
// note: `instanceof` was added in Qt 5.10
if (button.background && button.background instanceof Rectangle) {
button.background.color = "red"; // override style color
button.background.gradient = null; // some styles use a gradient
button.background.visible = true; // some styles may hide it in some situations
}
// Similar with the label element, IconLabel is used by all included QML styles.
if (button.contentItem && button.contentItem instanceof IconLabel) {
button.contentItem.color = "blue"; // override style color
button.contentItem.font.bold = true;
button.contentItem.font.pointSize = 20;
}
}
ColumnLayout {
anchors.fill: parent
spacing: 5
Button {
id: button1
text: "Select"
onClicked: selectDialog()
Layout.fillWidth: true
}
// These buttons should appear only after the user selects the choices on `Page2`
Button {
id: dialogA
text: "Freddie Mercury"
visible: dialogId === 1
Layout.fillWidth: true
onClicked: buttonClick(this)
}
Button {
id: dialogB
text: "David Gilmour"
visible: dialogId === 2
Layout.fillWidth: true
onClicked: buttonClick(this)
}
Button {
id: dialogC
text: "Mick Jagger"
visible: dialogId === 3
Layout.fillWidth: true
onClicked: buttonClick(this)
}
}
}
If you had a customized Button (like in the Qt docs example) then you could still do basically the same thing in buttonClick() but probably w/out worrying about the if (button.background ...) stuff (since you'd be sure your button has valid background/contentItem Items).
A better implementation of a "default" (Style-specific) Button but with custom colors/text properties would involve a subclass which uses Binding and/or Connections QML elements to control the properties and be able to reset them back to the current QtQuick Style defaults.

How make QML ListView not flickable?

I was wondering if there's any way for ListView to behave like a desktop control and not react with scrolling to mouse dragging?
I know about the interactive property, but I still want the ListView to react to clicks, mouse wheel, arrow keys, and have a ScrollBar.
For starters, setting interactive to false will pretty much immobilize the view.
There is a keyNavigationEnabled property which doesn't seem to work at this moment(this critical bug).
So will need to do a little extra work to get it to work as you want:
MouseArea {
anchors.fill: ll
onWheel: ll.flick(0, wheel.angleDelta.y * 5)
}
ListView {
id: ll
model: 50
width: 50
height: 200
spacing: 5
focus: true
interactive: false
boundsBehavior: Flickable.StopAtBounds
Keys.onPressed: {
if (event.key === Qt.Key_Up) flick(0, 500)
else if (event.key === Qt.Key_Down) flick(0, -500)
}
delegate: Rectangle {
width: 50
height: 50
color: "red"
MouseArea {
anchors.fill: parent
onClicked: console.log("clicked")
}
}
}
Interactivity is disabled, key navigation is implemented manually, and a background MouseArea is used to capture wheel events. Note that you don't have to do anything special to enable clicking on items for a non-interactive view, it works regardless of the view is interactive or not.

Resources