QML Signal for Orientation Change Complete - qt

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

Related

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.

Swaping between full screen and windowed mode

My question is related to this one: Full-screen desktop application with QML
Here is my MWE:
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window
{
property string windowFull: "FullScreen";
property string windowWindowed: "Windowed";
width: 400
height: 400
visible: true
title: "Example"
visibility: windowFull;
id: theWindow;
Button
{
onClicked:
{
if (theWindow.visibility === windowWindowed)
theWindow.visibility = windowFull;
else
theWindow.visibility = windowWindowed;
}
}
}
In this example I am trying to go from windowed mode to full screen and vice versa when clicking the button. My problem is that going full screen from windowed mode works, but from full screen to windowed does not. Are there any special requirements that has to be made in order to go windowed mode from full screen?
On Ubuntu, using Window.AutomaticVisibility is making the window visibilty as windowed (default window). Please check the QML window example.
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window
{
property string windowFull: "FullScreen";
property string windowWindowed: "Windowed";
width: 400
height: 400
visible: true
title: "Example"
visibility: windowFull;
id: theWindow;
Button
{
onClicked:
{
if (theWindow.visibility === Window.FullScreen)
theWindow.visibility = Window.AutomaticVisibility;
else
theWindow.visibility = Window.FullScreen;
}
}
}

How to make the Window to be as high as the WebEngineView when the latter's size is not constrained and natural

I use Qt 5.10.1 on up-to-date Windows 10 and the following simple program does not show any window:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtWebEngine 1.5
Window { id: w
visible: true
title: "Test"
// with this line, the program crashes before showing anything:
height: v.contentsSize.height
WebEngineView { id: v
anchors.left: w.left
anchors.right: w.right
anchors.top: w.top
onContentsSizeChanged: {
console.log(contentsSize) // no output if not both width and height properties of the web view are specified
w.height = contentsSize.height
}
// if any of the following 2 lines are omitted, the web view the ":-)" string in the web view does not show up and the window looks empty although anchors.left and anchors.right are set above and the height is set
// width: 100
// height: 100
// The following line crashes the program before showing the window
// height: v.contentsSize.height
Component.onCompleted: {
loadHtml(":-)");
}
}
}
I specifically want the window to be as high as the web view when its size is not constrained. Relevant documentation link: http://doc.qt.io/qt-5/qml-qtwebengine-webengineview.html#contentsSize-prop.
// with this line, the program crashes before showing anything:
height: v.contentsSize.height
That is because contentsSize is undefined at this point .. you haven't loaded any content yet, the qml engine crashes with undefined height. So just leave Window with no height .. equivalent to (height:0)
I specifically want the window to be as high as the web view when its
size is not constrained.
Then don't anchor the WebEngineView .. that's the problem, because your anchoring - which is not complete - will give WebEngineView an initial height following initial default height of Window, but you never change it later after loading .. so even Window will not be able to resize to a smaller height!
To do that safely with minimum change, set height/width of WebEngineView to any value initially .. then once the contents are loaded, reset WebEngineView height / width to contentsSize .. so thatWindow can resize to that height.
Window { id: w
visible: true
title: "Test"
WebEngineView {
id: v
width:1
height:1
onContentsSizeChanged: {
console.log(contentsSize) // no output if not both width and height properties of the web view are specified
//
// here you can set web view height so that Window heigth is same as webview
width = contentsSize.width
height = contentsSize.height
// and Window height
w.height = contentsSize.height
}
Component.onCompleted: {
loadHtml(":-)");
}
}
}

Why does my QML background transparency break depending on width setting?

I'm running into some strange QML behavior. Basically, I have a TabBar header with several tabs running across it. I'd like the background element to be mostly the same for each of them, but some of them I want to be able to dynamically change the color of. So I have a component:
Component {
id: standardBackground
Rectangle {
opacity: parent.parent.checked ? 0 : (parent.parent.pressed ? 0.8 : 1)
color: tabColor
}
}
And for each TabButton, I'm doing:
TabButton {
text: qsTr("Tab 1")
background: Loader { sourceComponent: standardBackground }
height: 60
}
This works perfectly, but I'm running into some really strange errors. First off, running it this way gives me the following QML warning:
QML TabButton: Binding loop detected for property "implicitWidth"
So I figured I could fix this by adding: width: parent.width to the Rectangle in my component. This does silence the warning, but for some reason, it makes it so that the first tab will always be transparent regardless of whether or not it's clicked. This only affects the first tab. I have no clue why this would happen.
However, when I set width: <anything>, then this fixes both problems: No warnings and correct transparency. Playing around with different settings for the width causes no noticeable changes, as long as it's positive. So I have it set to 1. If I set it to 0, I get the same "implicit width" warnings.
So a couple different questions:
Why does the transparency of the component break when I set width: parent.width?
Why can I set width to any constant value without it affecting the GUI at all?
Is there a better way of silencing the warning about implicit width?
Here is my full code (simplified to less tabs):
import QtQuick 2.6
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
import QtQuick.Controls.Universal 2.0
import Qt.labs.settings 1.0
import QtQuick.VirtualKeyboard 2.1
import QtQuick.VirtualKeyboard.Settings 2.1
import "DataEntry"
ApplicationWindow {
id: window
width: 1280
height: 1024
visible: true
title: "Hello World"
property var tabColor: "#353637"
property var dummy: InputContext.focus
Settings {
id: settings
property string style: "Universal"
}
Component {
id: standardBackground
Rectangle {
opacity: parent.parent.checked ? 0 : (parent.parent.pressed ? 0.8 : 1)
color: tabColor
width: 1
}
}
header: TabBar {
id: bar
width: parent.width
height: 60
TabButton {
text: qsTr("Tab 1")
background: Loader { sourceComponent: standardBackground }
height: 60
}
TabButton {
text: qsTr("Tab 2")
background: Loader {
sourceComponent: standardBackground
function getTabColor(error){
if (error)
return '#cccc00'
return window.tabColor
}
property var tabColor: getTabColor(hasError)
}
height: 60
}
}
StackLayout {
id: viewStack
width: parent.width
anchors.fill: parent
currentIndex: bar.currentIndex
tab1 {
}
tab2 {
}
}
}
As we are on SO I tend to answer only one question. For you, I choos the question for the binding loop.
The reason for that binding loop is documented here.
You do not specify a size for the Loader so the implicit width of the Loader is set to the width specified by the loaded Item. Here you set the size to be the same as the Loader's size. Now this would not be a problem, and the result would just be 0
Now we stir in the Button which also has an implicitSize set to its styling items. Here the Loader is instantiated widht width 0 and then resized to fill the implicitWidth of the Button which is (without a sized background) depending on the text and the paddings.
And now we update the round. So, the implicitWidth of the Rectangle is depending on the width of the Loader whose implicitWidth is depending on the Rectangles width. Further the Loaders width is depending on the Buttons width, which is depending on its implicitWidth and which is in turn depending on its childrenRect.width...
A binding loop is easily detected even if there are no direct problems, as the system is stabilizing in the first iteration.

QML Applicationwindow resize stutter

I am encountering a problem that I hope is because I am bad at coding QML and not because of some fundamental bug in Qt.
Whenever I resize the application window in the horizontal direction (width change) the window doesn't resize to where I release the mouse but "snaps" back to its minimumwidth. I have managed to strip it down to the most basic requirements to reproduce the bug.
Not releasing the mousepress causes the width to dance back and forth between the minimumwidth and where the mouse is.
Removing item removes the bug
Resizing vertically (changing height) MAY sometimes crashes the application if the mouse isn't released for a long time (eg is in state of resizing)
It is practically impossible to resize because of this
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: root
visible: true
minimumHeight: 768
minimumWidth: 1024
title: qsTr("Test")
color: "#292525"
Item {
width: 0.9*parent.width
height: 0.1*parent.height
}
}
Any idea why this is happening?
You have a form of subtle binding loop. QtQuickControls' ApplicationWindow attempts to keep the size of the window's content to match that of the content inside it, called contentItem, which all children of the ApplicationWindow are (silently) reparented into, but you are making the size of your content dependent on the window that it is residing in.
So, you resize your window, which changes the size of your Item, which changes the size of the contentItem, which makes ApplicationWindow resize your window (fighting with you).
Something like this might work:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: root
visible: true
minimumHeight: 768
minimumWidth: 1024
title: qsTr("Test")
color: "#292525"
// This item will just match the Window's size...
Item {
anchors.fill: parent
// ... and here, we'll fill a part of it with a rectangle.
Rectangle {
color: "red"
width: 0.9*parent.width
height: 0.1*parent.height
}
}
}

Resources