Popup in qml : (closePolicy: Popup.NoAutoClose) - qt

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.

Related

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.

QML Glow Inside a RowLayout

I am using Qt 5.15 Quick 2 QML to create a row of custom buttons in a window. When I have a standalone custom button things appear to work fine, but when I put them in a RowLayout there appears to be severe clipping and artifacting issues.
A minimum reproducible example might look like:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
RowLayout
{
anchors.fill:parent
anchors.margins: 25
Button
{
text: "Click Me"
Layout.fillWidth: true
}
CustomButton
{
text: "That Boy Don't Glow Right"
}
Button
{
x: 100; y:100
text: "Click Me"
Layout.fillWidth: true
}
}
}
with the custom control
import QtQuick 2.0
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
Button {
id: control
text: "Click Me"
Glow {
anchors.fill: control
radius: 64
spread: 0
samples: 128
color: "red"
source: control
visible: true
}
}
with example output:
One potential fix is to add change the Glow to
Glow {
anchors.fill: control
width: parent.width
height:parent.height
x:control.x
y:control.y
parent: control.parent
...
But this doesn't seem right. First, it's not obvious to me where parent.width and control.x and control.parent are bound from and what happens in single and multiple nesting. If a CustomButton is placed inside another control with id control, would it rebind the property? And it appears if a RowLayout is placed inside a RowLayout, then it would require parent: control.parent.parent. In my actual code there is some non-trivial positioning to allow margins for a drop shadow, too, and the CustomButton is in another container so the actual code that works is: x:control.x + parent.pad/2 and parent:control.parent.parent.parent which is, frankly, ridiculous and assumes that non-standard fields in the parent are always available.
Is there a better way? Was hoping I could keep the button's ability to glow itself.
According to the docs:
"Note: It is not supported to let the effect include itself, for instance by setting source to the effect's parent."
So it's fortunate that you were able to get your example to work at all. One way to avoid using the parent as a source is to point the Glow object at the Button's background object:
Button {
id: control
Glow {
source: control.background
}
}

QML - Prevent MouseArea's positionChanged signal to propagate in ScrollView

This post is a copy of a message I already sent on the Qt forum but I couldn't get an answer.
You can find the original post here: https://forum.qt.io/topic/113890/prevent-mousearea-s-positionchanged-signal-to-propagate-in-scrollview/4
If the link is dead, everything is copied below:
I am trying to handle a positionChanged signal in a MouseArea (to create kind of a drag&drop effet) that is in a ScrollView.
My problem is that after the mouse travelled a short distance, the parent ScrollView seem's to get the focus (the scrollbar appears) and I stop to receive positionChanged signals.
The objective would be to receive the positionChanged signal (even if the mouse gets out of my MouseArea & over the ScrollView as long as my left mouse button stays pressed) without propagating the signal to the ScrollView.
I have 3 separate examples. This is a simple QML application that should be easy to run.
The two first examples work. The third does not work.
What is "working":
Press the mouse button down on the MouseArea
Move the mouse around without releasing the button
The message that logs coordinates should never stop printing, wherever you are on screen until you release the mouse button.
For the third example, I get logs until the mouse moves too much and all the updates stop.
Only ScrollView (works)
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow{
id: root
visible: true
width: 1200
height: 600
ScrollView {
clip: true
anchors.fill: parent
MouseArea {
width: 300
height: 300
onPositionChanged: {
console.log('Moved', mouseX, mouseY)
}
}
}
}
Only ColumnLayout (works)
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow{
id: root
visible: true
width: 1200
height: 600
ColumnLayout {
MouseArea {
width: 300
height: 300
onPositionChanged: {
console.log('Moved', mouseX, mouseY)
}
}
}
}
ColumnLayout inside a ScrollView (does not work)
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow {
id: root
visible: true
width: 1200
height: 600
ScrollView {
clip: true
anchors.fill: parent
// note: It does not work for ColumnLayout, Column, Row or RowLayout. If I use a Item here, it works
ColumnLayout {
MouseArea {
width: 300
height: 300
onPositionChanged: {
console.log('Moved', mouseX, mouseY)
}
}
}
}
}
You can find a video of the behavior here: https://i.imgur.com/rIlWnhu.mp4
I press and release the mouse without moving: I get the pressed & released events correctly
I press and move the mouse: I get the pressed event, the move event, then it stops. No more move or released events.
I press and move the mouse without going too far from the position where I pressed the mouse: It works until I get too far
Note: I don't get any Released or Exited event, but the containsPressed property is correctly updated (ie: when I no longer receive events, its value is false). This is the property that I use to display the "Mouse pressed" text.
Is this something I do wrong with the ScrollView/ColumnLayout combo or is this a Qt bug ?
Add this to your MouseArea in your third example:
preventStealing: true
For more info see:
https://doc.qt.io/qt-5/qml-qtquick-mousearea.html#preventStealing-prop

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.

QML Signal for Orientation Change Complete

I am working on an ESRI AppStudio app (AppStudio 3.1, Qt 5.11) for iPad and need to do some resizing of a QML control when the orientation changes. I found this page which seems to describe the official way to do this: https://wiki.qt.io/QML_orientation_observer
import QtQuick.Window 2.2
Rectangle {
property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation || Screen.primaryOrientation === Qt.InvertedPortraitOrientation
onIsPortraitChanged: console.log("isPortrait", isPortrait)
}
However, I have found the statement on that page that the binding will be fired after the height and width changes are completed to be incorrect. What I saw when I implemented this is that onIsPortraitChanged does indeed fire when the orientation changes but it does so before the orientation change animation completes and before the width of the app is resized. Is there a way I can trigger my code after the width is finished changing?
Here's a solution that I found but it will only work for devices where the app is full screen and there might be a cleaner way to do this.
import QtQuick.Window 2.2
Window {
id: app
visible: true
width: 640
height: 480
Rectangle {
anchors.fill: parent
onWidthChanged: {
if(app.width === Screen.width || app.width === Screen.height) {
//calculate new size
}
}
}
}
I have no problem getting new width with correct signal for orientationchanged
import QtQuick.Window 2.12
Window {
id: app
visible: true
width: 640
height: 480
Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.PortraitOrientation
...
...
Connections{
target: my_object
Screen.onPrimaryOrientationChanged:{
console.log("orinetation changed, width: " + width )
}
}
}

Resources