QML Applicationwindow resize stutter - qt

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

Related

Why is my QML GroupBox not sizing properly within a layout?

I'm trying to make two group boxes appear next to each other so that each one occupies 50% of the window. However, it looks like the width of each GroupBox is somehow changed depending on the GroupBox title length.
If the GroupBox title is the same for both GroupBox's, it will be 50% of the window. If they are not the same, the GroupBox with the longer title will occupy more of the screen.
It doesn't make sense to me for this to happen, how can I fix it so the length of the title doesn't effect the size of the GroupBox in a layout?
Here's sample code to reproduce the issue...
AppGroupBox.qml
import QtQuick 2.0
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.12
GroupBox {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
spacing:0
label.x: 0
}
AppRowLayout.qml
import QtQuick 2.0
import QtQuick.Layouts 1.12
RowLayout {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
spacing: 0
}
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Window {
width: 640
height: 480
visible: true
AppRowLayout {
anchors.fill: parent
AppGroupBox {
title: "Short Name"
Layout.fillWidth: true
}
AppGroupBox {
title: "Much Longer Name"
Layout.fillWidth: true
}
}
}
Qt will distribute the free space relative to the Layout.preferredWidth (or implicitWidth if that isn't defined). So, a group box with a longer title will get more space by default, as its implicitWidth is larger.
The solution is to use a fixed preferredWidth for all elements in the RowLayout:
GroupBox {
...
Layout.preferredWidth: 50 // or any other fixed value.
Layout.minimumWidth: implicitWidth // OPTIONAL: may be usefull on small screens to ensure the box is not made smaller than the title width
...
}
Note on attached properties:
Layout.alignment is an attached property available on the children of a Layout (RowLayout, GridLayout or ColumnLayout). Setting it directly inside a RowLayout object is useless (except when the RowLayout itself is a child of another Layout item.

Qt Animating Window Appearance

In Qt 5.15 Quick 2 code, setting a QtQuick.Dialogs FileDialog visible property to true causes it to animate onto the screen in a "blorping" motion. I am developing a Gantt chart where clicking on an item in the timeline will bring up a window to edit its properties. Is there a way to not just have the Frame/Window appear instantly but instead to "blorp" out of the item clicked like the FileDialog does from the top of the window? I notice that the shape and interior controls of the FileDialog are morphed and then solidify to indicate that the dialog is being introduced and which window it is coming from. In my case I hope to have the window pop out of the control it will edit the properties of and, when finished, squirt back inside to reinforce that those properties are being pushed into the item being edited. Is this possible?
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Dialogs 1.2
import QtQuick.Controls 2.5
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Button
{
onClicked: chooseFile.visible = true
text: "Click Me"
}
FileDialog
{
id: chooseFile
title: "Save Me!"
//folder: shortcuts.home
selectExisting: true
}
}

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

Top item in a ListView disappears completely even when only partially ouside bounds. How can I fix this?

I'm learning to use Qt and QML. Right now, I'm trying to use a ListView, and I mostly got it to work, except for this one little visual bug.
When I run the code, at first it looks fine. But if I scroll a little bit, the top item disappears completely. It only appears again when scrolling back enough so that it is entirely within bounds. In the mean time, there's only a ugly blank spot in the list. That happens with every item when it goes over the top bound.
I want the items to be partially drawn. The library is clearly capable of doing this, since this problem doesn't happen in the lower bound, but I simply cannot figure out how to do it.
Here's a simplified version of my code:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
width: 360
height: 520
visible: true
title: "Qml.Net"
ListView {
anchors.fill: parent
spacing: 100
model: ["#111111", "#222222", "#333333", "#444444", "#555555", "#666666"]
delegate: Item {
Rectangle {
width: 400
height: 100
color: modelData
Text {
anchors.centerIn: parent
text: modelData
}
}
}
}
}
And here are some pictures of the problem. First image is correct, second image shows the error. Also, notice how the bottom item is correctly drawn.
Correct at first
Wrong after a little bit of scrolling
Qt 5.12
The problem is caused by the "spacing" property that is unnecessary in your case. The solution is to remove that property and rewrite the logic as follows:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
width: 360
height: 520
visible: true
title: "Qml.Net"
ListView {
anchors.fill: parent
model: ["#111111", "#222222", "#333333", "#444444", "#555555", "#666666"]
delegate: Rectangle {
width: parent.width
height: 100
color: modelData
Text {
anchors.centerIn: parent
text: modelData
}
}
}
}

How to make rectangle height fill ScrollView

I have the following QML code:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
Window {
id: win
width: 1024
height: 768
visible: true
ScrollView {
id:scrollView
anchors.fill: parent
Rectangle{
id:rect
z:5
color:"red"
width: 2048
height: win.height
border{
color: "black"
width: 2
}
}
}
}
In this code the larger Rectangle makes the horizontal scrollbar correctly appear. However, since the scrollbar takes some height from the window, the vertical scrollbar appears too.
How can I make the Rectangle fill only available space in my ScrollView so that vertical scrollbar won't show up? Using something like win.height - <someNumber> is not acceptable. Adding verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff is also not acceptable cause it hides some content on bottom of rect.
Generally speaking ScrollView is not meant for such usage. It is more a container to lay out items and have them shown through the provided scrollbar. Binding loops can pop here and there if bindings are not properly set. Also Flickable + a custom scrollbar (e.g. the ones available here) can perfectly fit your needs.
That said, viewport property provides the desired (cross-platform) workaround for the problem. The documentation states:
The viewport determines the current "window" on the contentItem. In other words, it clips it and the size of the viewport tells you how much of the content area is visible.
Hence the height of the child Item can be set according to the height of the viewport. A final simple example with an Image (cute kitty incoming) would look like this:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
Window {
id: win
width: 300
height: 300
visible: true
ScrollView {
id:scrollView
anchors.fill: parent
Image{
height: scrollView.viewport.height
source: "http://c1.staticflickr.com/9/8582/16489458700_c9d82954b7_z.jpg"
}
}
}

Resources