QtQuick and StackLayout - dynamically inserted component is not resized properly - dynamic

I have a probably simple question regarding the dynamic insertion of components into a stack layout in QtQuick 2.0. See the following code:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: mainWindow
minimumWidth: 640
minimumHeight: 480
visible: true
Component {
id: stackItemComponent
Item {
Rectangle
{
color: "blue"
anchors.fill: parent
}
}
}
Item {
anchors.fill: parent
StackLayout {
id: stack
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
var item = stackItemComponent.createObject(stack)
// Activating this does not solve the problem
//item.Layout.fillWidth = true
//item.Layout.fillHeight = true
}
}
}
}
The version shown inserts the simple component into the stack layout by clicking into the window but the inserted rectangle is not resized as expected. As I read in the documentation the attached properties "Layout.fillWidth" and "Layout.fillHeight" default to "true" in this type of layout so there should be no need to set them manually. But if I do so, it does not solve the problem either. It needs a manual resize of the window to to show the layout correctly.
What do I miss here?

Related

How can I animate a Dialog to enter from outside the screen?

This question is similar to - but no the same as Moving qml Item out of left side of window, because my question is about Dialogs, instead of Items in general. The difference is explained below.
I have a Qt Dialog which I want to enter the screen from the left.
The first approach I took was setting the dialogs x property to -width and then adding a Behavior on x or a manually triggered NumberAnimation.
This approach however failed, because setting negative x values is not allowed and the value gets changed to 0 immediately.
This post provides a solution for this issue, by using anchors and AnchorChanges and transitions - but only for Items.
However, the Dialog type does neither provide states, nor anchors but only coordinates.
So my question stands: How can I have a QML Dialog animate from the left outside the screen into view?
Here's a minimal code sample, that demonstrate the x property being reset to 0:
import QtQuick 2.7
import QtQuick.Controls 2.3
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Dialog Demo")
Dialog {
id: dialog
width: 200
height: 200
x: -width
Text {
anchors.centerIn: parent
text: "Ok?"
}
standardButtons: Dialog.Ok
onOpened: x = 100
Behavior on x { NumberAnimation{ duration: 1000 } }
}
Component.onCompleted: dialog.open()
}
You can use the enter-transition that is inherited from Popup:
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.3
Window {
id: window
visible: true
width: 600
height: 600
Dialog {
id: dialog
width: 300
height: 300
enter: Transition {
NumberAnimation { properties: "x,y"; from: -300; to: 150 }
}
}
Button {
anchors.centerIn: parent
onClicked: dialog.open()
}
}
There seems to be a Bug with the Dialog. As soon as the Dialog has some content, it fails. I have not discovered all depths of it, but wrapping everything in an Item seems to help. Compare for this:
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
Dialog {
id: dialog
width: 300
height: 300
enter: Transition {
NumberAnimation { properties: "x,y"; from: -300; to: 150; duration: 5000 }
}
// HAVE A BUTTON IN THE DIALOG -> POSITIONING FAILS
Button {
anchors.centerIn: parent
}
}
Button {
text: 'open'
anchors.centerIn: parent
onClicked: dialog.open()
}
}
and
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
Dialog {
id: dialog
width: 300
height: 300
enter: Transition {
NumberAnimation { properties: "x,y"; from: -300; to: 150; duration: 5000 }
}
Item { // WRAP IT IN THE ITEM -> WORKS FOR ME
anchors.fill: parent
Button {
anchors.centerIn: parent
}
}
}
Button {
text: 'open'
anchors.centerIn: parent
onClicked: dialog.open()
}
}

QML TextArea won't scroll

I added a simple TextArea in my application. Unfortunately, I can't scroll through the text even if its contentHeight bypasses its height.
Here is the code:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: appWindow
visible: true
width: 480
height: 640
TextArea{
anchors.fill: parent
anchors.margins: 100
wrapMode: TextEdit.Wrap
Component.onCompleted: {
console.log("width:", width)
console.log("contentWidth:", contentWidth)
console.log("height:", height)
console.log("contentHeight:", contentHeight)
}
onTextChanged: {
console.log("width:", width)
console.log("contentWidth:", contentWidth)
console.log("height:", height)
console.log("contentHeight:", contentHeight)
}
}
}
TextArea is not scrollable by default, mainly to make it possible to have multi-line editors as part of a scrollable page without having nested Flickables, which often gives sub-optimal experience. In order to make a standalone TextArea scrollable, you can attach it to a Flickable as illustrated in the documentation.

Center elements inside Scrollview

I have a problem with centering QML objects in a ScrollView. I want to scroll the images and other QML elements and they should be centered. But they are always sticked to the top left angle.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow{
id: appWindow
width:Screen.width
height:Screen.height
visible: true
ScrollView {
anchors.fill: parent
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: 800
height: 800
color : "yellow"
}
}
}
You have two aspects to take in account. Directly from the docs:
Only one Item can be a direct child of the ScrollView and the child is implicitly anchored to fill the scroll view.
So you could not have more than one Rectangle, just a container for all the Rectangles (which actually are images, as stated in your question).
Moreover it should be noted, again from the docs, that:
The width and height of the child item will be used to define the size of the content area.
Hence, you need only one child for the ScrollView and ensure that it takes the correct size from the parent. I would use a ColumnLayout for the purpose. Final sample code here:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
ApplicationWindow{
id: appWindow
width: 200
height: 100
visible: true
ScrollView {
anchors.fill: parent
ColumnLayout { // unique child
spacing: 10
width: appWindow.width // ensure correct width
height: children.height // ensure correct height
// your children hereon...
Repeater {
model: 4
delegate: Rectangle {
Layout.alignment: Qt.AlignHCenter
width: 50
height: 50
color : "yellow"
}
}
}
}
}
EDIT
According to the OP the provided solution does not perfectly meet his needs and that's pretty reasonable. In particular:
no horizontal scrollbar is shown if the window is resized horizontally
the horizontal scrollbar is shown as soon as the vertical one is shown
Both the problems are related to the approach used. Problem 1 is caused by the binding between the parent width and the ScrollView width: since the visible width is always equal to the total width, no horizontal scroll is shown, even if the contained items are larger than the window. Problem 2 is a consequence of the 1: since the width is equal to application, as soon as a vertical scrollbar is added, the horizontal one is also added to show the horizontal space covered by the vertical scrollbar.
Both the problems can be solved by changing the width binding to be either equal to the contained items width (to solve problem 1) or equal to the width of the viewport (solve problem 2), as also discussed in this other answer. Finally, anchoring should be removed to avoid binding loops. Here is a complete example working as expected:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
ApplicationWindow{
id: appWindow
width: 200
height: 100
visible: true
ScrollView {
id: scroller
width: appWindow.width // NO ANCHORING TO AVOID binding loops!
height: appWindow.height
ColumnLayout { // <--- unique child
spacing: 10
width: Math.max(scroller.viewport.width, implicitWidth) // ensure correct width
height: children.height // ensure correct height
// your children hereon...
Repeater {
model: 3
delegate: Rectangle {
Layout.alignment: Qt.AlignHCenter
width: 150
height: 150
color : "yellow"
}
}
}
}
}
is bound to the window width horizontal scrolls are not shown, even if contained items are larger than the window
From the doc (http://qt-project.org/doc/qt-5/qml-qtquick-controls-scrollview.html) :
Only one Item can be a direct child of the ScrollView and the child is implicitly anchored to fill the scroll view.
So you can't achieve what you want by anchoring the content. You have to change the size and the anchoring of the ScrollView
For example :
ApplicationWindow{
id: appWindow;
width:Screen.width;
height:Screen.height;
visible: true;
ScrollView
{
anchors.centerIn: parent;
width: Math.min(content.width + 30, appWindow.width);
height: Math.min(content.height, appWindow.height);
Rectangle
{
id: content;
width: 800;
height: 800;
color : "yellow"
}
}
}
You can insert a Rectangle or other similar QML items you like as a middle layer between ScrollView and the QML item you need to center and set its color to "transparent". This should be a cross-platform solution.
I have modified your code for example:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
id: appWindow
width:Screen.width
height:Screen.height
visible: true
ScrollView {
anchors.fill: parent
Rectangle {
width: Math.max(appWindow.width, rect.width)
height: Math.max(appWindow.height, rect.height)
color: "transparent"
Rectangle {
id: rect
anchors.centerIn: parent
width: 800
height: 800
color : "yellow"
}
}
}
}
I use Qt 5.5.

QML TabView in ColumnLayout

I am trying to modify Gallery example. I want to add Button under TabView. So, I put TabView and Button into ColumnLayout, here is code:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Window 2.0
Window {
visible: true
title: "settings"
width: 600
height: 400
ColumnLayout{
anchors.fill: parent
TabView {
anchors.right: parent.right
anchors.left: parent.left
Tab {
title: "Controls"
Controls { }
}
Tab {
title: "Itemviews"
Controls { }
}
Tab {
title: "Styles"
Controls { }
}
Tab {
title: "Layouts"
Controls { }
}
}
RowLayout{
anchors.right: parent.right
anchors.left: parent.left
Button{
text: "ok"
}
}
}
}
However, when I resize window okButton stands under tab controls. How should I fix code?
When you have defined a Layout, each element added has access to specific properties related to the layout itself. These properties are useful to position the element inside the space covered from the layout. Confront what is described here.
Hence, you should modify the ColumnLayout like this:
ColumnLayout {
anchors.fill: parent
TabView {
id:frame
enabled: enabledCheck.checked
tabPosition: controlPage.item ? controlPage.item.tabPosition : Qt.TopEdge
Layout.fillHeight: true // fill the available space vertically
Layout.fillWidth: true // fill the available space horizontally
Layout.row: 0 // item in the first row of the column
anchors.margins: Qt.platform.os === "osx" ? 12 : 2
Tab {
id: controlPage
title: "Controls"
Controls { }
}
Tab {
title: "Itemviews"
ModelView { }
}
Tab {
title: "Styles"
Styles { anchors.fill: parent }
}
Tab {
title: "Layouts"
Layouts { anchors.fill:parent }
}
}
Button {
text: "ok"
Layout.row: 1 // item in the second row of the column
Layout.alignment: Qt.AlignCenter // simple center the button in its spatial slot
}
}
You don't need a RowLayout for the button. It should be placed in the second row of the ColumnLayout you have defined, since it is a simple component. A sub-layout could be useful in case of multiple elements on the same row, e.g. two or more buttons.
Note also that anchoring is just used for the ColumnLayout to "stretch" and fit the window. All the other operations are executed via the layout properties. For general rules take a look at this other article.

item inside component access

I have the following qml file:
import QtQuick 1.0
Component{
Column{
id: interHeader;
Item{
id:interItem
height: 300
width: 200
Text{
id:title
text:"Text"
anchors.centerIn: parent
font.bold: true
elide:"ElideRight"
color: "Black"
}
}
Item {
width: parent.width
height: 100
//onClick event
MouseArea {
anchors.fill: parent
onClicked:{
console.log("Ok");
}
}
}
}
}
The problem is that I need to assign some KeyNavigation to the interItem.
I want to access the interItem from another qml file.
How can this be done?
There really is no benefit of using Component in a completely separate QML file. Remove Component and name your Qml file with a capital letter - e.g. InterHeader
Then define a property under your root item. For example:
import QtQuick 1.0
Item {
id: interHeader
property variant keyActionUp
Keys.onUpPressed: keyActionUp
}
OR
You can use the Connections function to execute callbacks for signals from interHeader.
http://doc.qt.nokia.com/4.7-snapshot/qml-connections.html