Scaling and positioning in QML - qt

I'm developing a Qt5.11.1 QML application that runs into a QQuickWidget. The resize mode is set to SizeRootObjectToView. Hence, whenever I resize the QMainWindow I see my QML root object that scales too.
Inside I have some images anchored to fill the parent, and they are scaled as expected. Instead I have issues with smaller images or text that should maintain the same relative position and size.
I begin with absolute position and size when ratio is 1:1. Example: the root item has a size of 1920x1080 px, and I must place the other items (mainly images and texts) to given coordinates.
When the root changes its size all the elements should follow it. I tried this:
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtGraphicalEffects 1.0
Rectangle {
id: root
visible: true
color: "black"
property real ratio: root.width / 1920
readonly property real x_CenterGauge: 502
readonly property real y_CenterGauge: 489
Image {
x: x_CenterGauge * ratio
y: y_CenterGauge * ratio
scale: ratio
}
}
but this doesn't work because the root.width property (and in turn ratio) doesn't change when I resize the window. But it actually resize the root element because any anchored item will resize too! I get a change only if I maximize/minimize the window.
I read this article and this question, but I still don't understand how to handle the resising in QML.

In testing it is the property scale that seems to be a problem
By modifying width and height instead it solves the problem
Rectangle {
id: root
visible: true
color: "black"
property real ratio: root.width / 1920
readonly property real x_CenterGauge: 202
readonly property real y_CenterGauge: 489
Image {
x: root.x_CenterGauge * root.ratio
y: root.y_CenterGauge * root.ratio
width: implicitWidth * root.ratio
height: implicitHeight * root.ratio
//scale: ratio
}
}

Related

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(":-)");
}
}
}

qml virtual keyboard: keyboardDesignWidth and Height

I am looking at the QML Style for the virtual keyboard. What is the purpose of keyboardDesignWidth and Height? I seem to have a lot of trouble managing the width and height of the keyboard and can never set it to how I want it. Setting the keyboardHeight and Width directly also does not help much.
The issue is that the component background size is somehow computed behind the scenes. So, even when I have the keyboard buttons and size how I want, the extraneous background covers some of my other control and it is very difficult to have a fine grained control over the size of the keyboard.
What is the right way to control the width and size of the virtual keyboard directly?
To Quote from the Documentation
The keyboard size is automatically calculated from the available width; that is, the keyboard maintains the aspect ratio specified by the current style. Therefore the application should only set the width and y coordinates of the InputPanel, and not the height.
So if you want to have a specific height, you need to set the width accordingly.
What is the right way to control the width and size of the virtual keyboard directly?
e.g.
InputPanel {
anchors.fill: parent
anchors.leftMargin: 100
anchors.rightMargin: 100
}
e.g.
InputPanel {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
width: 30
}
So what's the deal with the keyboardDesignHeight/Width? Well this seems to be the dimensions of the keyboard, when it is not necessary to scale it:
scaleHint : real
The keyboard style scale hint. This value is determined by dividing keyboardHeight by keyboardDesignHeight. All pixel dimensions must be proportional to this value.
This property is readonly!
So setting those will not disable the automatic resizing of your input panel in dependence of the width.
You might use them maybe, to calculate a ratio, and from this set the width to achieve your desired height.
Maybe this example helps you to understand this property:
import QtQuick 2.6
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import QtQuick.VirtualKeyboard 2.0
ApplicationWindow {
id:appwindow
visible: true
width: 800
height: 600
title: qsTr("Test")
InputPanel {
id: ip
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
width: 800
Component.onCompleted: console.log(Object.keys(ip.keyboard.style).sort())
}
Slider {
id: sl
from: 0
to: 3000
}
Binding {
target: ip.keyboard.style
property: 'keyboardDesignHeight'
value: sl.value
}
}

QML ApplicationWindow: set minimum size to fit content

I would like to set the minimum width and height of my QML Application window, so that the content item is fully visible (not clipped).
import QtQuick 2.5
import QtQuick.Controls 1.4
ApplicationWindow {
visible: true
width: 100
height: 100
title: "test"
minimumWidth: circle.width
minimumHeight: circle.height // + menuBar.height
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: circle
anchors.centerIn: parent
width: 200
height: 200
color: "red"
radius: width * 0.5
}
}
Here is the result:
As you can see, setting the minimum width works fine. The minimum height seems to be off by the height of the menu bar. The problem is, adding something like menuBar.height does not work as this property does not exist.
So the question is: how do I set the size of the ApplicationWindow, so that the content item (given by width/height or implicitWidth/implicitHeight) is not clipped?
Note: In reality, instead of a red circle, the content item serves as a game canvas, which I would like to resize dynamically.
As always with the old QtQuick.Controls 1.x the only way to help yourself is, to look at the (undocumented/internal) properties. For the MenuBar those are:
objectName
menus
__contentItem
__parentWindow
__isNative
style
__style
__menuBarComponent
objectNameChanged
menusChanged
nativeChanged
contentItemChanged
styleChanged
__styleChanged
__menuBarComponentChanged
__contentItem seems to be interesting, and it features a height - as soon as it is instantiated.
So we can define the height of the ApplicationWindow as such:
minimumHeight: contentItem.childrenRect.height
+ (menuBar.__contentItem ? menuBar.__contentItem.height : 0)

Adjusting QML Image display size

I have a QML window with a nested RowLayout. In the inner row I have two images. The source .png files for these images are (intentionally) rather large. When I attempt to set the height property on these images to make them smaller, they are still drawn large.
Desired Appearance:
Actual Appearance:
The only way I have been able to get them to be small is to set the sourceSize.height:100 instead of height:100; however, this is not what I want. I want them to be able to scale up and down without reloading.
How can I fix my QML so that the images take on the height of their containing RowLayout?
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
width:600; height:300
visible:true
Rectangle {
color:'red'
anchors { top:header.bottom; bottom:footer.top; left:parent.left; right:parent.right }
}
header:RowLayout {
id:header
spacing:0
height:100; width:parent.width
RowLayout {
id:playcontrol
Layout.minimumWidth:200; Layout.maximumWidth:200; Layout.preferredWidth:200
height:parent.height
Image {
// I really want these to take on the height of their row
source:'qrc:/img/play.png'
width:100; height:100
fillMode:Image.PreserveAspectFit; clip:true
}
Image {
source:'qrc:/img/skip.png'
width:100; height:100
fillMode:Image.PreserveAspectFit; clip:true
}
}
Rectangle {
color:'#80CC00CC'
Layout.minimumWidth:200
Layout.preferredWidth:parent.width*0.7
Layout.fillWidth:true; Layout.fillHeight:true
height:parent.height
}
}
footer:Rectangle { height:100; color:'blue' }
}
When using layouts, never specify the width or height of the item; use the Layout attached properties instead. The layout itself will set the width and height, effectively overriding whatever you set.
So, for your images, replace
width:100; height:100
with
Layout.preferredWidth: 100
Layout.preferredHeight: 100
This is documented here. Specifically, the width and height are only used as a "final fallback", and they won't behave as you'd expect.
There are other places in your code where this occurs:
playcontrol sets height: parent.height (filling the width and height of the parent is the default behaviour for layouts, so this shouldn't be necessary anyway).
The Rectangle within the playcontrol layout also sets height: parent.height.

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