QML GridLayout does not obey my specified cell arrangements - qt

In this code, some items are invisible at first. I want them to be visible on the click of a button at the place where they have been placed by me.
In order to leave space for them, I have placed the other item where it will be shown when hidden options will be visible.
My problem is that GridLayout does not obey the following cell positions set in code when other items are invisible.
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
Window {
visible: true
height: 500; width: 500
GridLayout {
id: gridLayout
property bool secondScreenOptionsVisible: false
property int hmmiButtonRow: 0
property int hmmiButtonCol: 0
Rectangle {
id: hmmi; visible: gridLayout.secondScreenOptionsVisible
Layout.row: gridLayout.hmmiButtonRow; Layout.column: gridLayout.hmmiButtonCol;
height: 50; width: 50; color: "pink";
Layout.alignment: Qt.AlignTop
Text { text: "HMMI"; anchors.centerIn: parent }
}
property int optionsButtonRow: 1
property int optionsButtonCol: 0
Rectangle {
id: optionsButton; visible: gridLayout.secondScreenOptionsVisible
Layout.row: gridLayout.optionsButtonRow; Layout.column: gridLayout.optionsButtonCol;
height: 50; width: 50; color: "red"
Layout.alignment: Qt.AlignTop
Text { text: "Options..."; anchors.centerIn: parent }
}
property int flipperControlRow: 3
property int flipperControlCol: 0
Rectangle {
id: flipperControl;
Layout.row :gridLayout.flipperControlRow; Layout.column: gridLayout.flipperControlCol;
height: 200; width: 50;
color: "brown";
Layout.rowSpan: 4
Layout.alignment: Qt.AlignTop
Text { text: "Flipper"; anchors.centerIn: parent }
}
}
}
Output:
When all the items are visible:
When other two items are hidden, the GridLayout does not obey the rules.
I want GridLayout to obey the cell positions set by me, irrespective of whether other items are visible or not.
Please help.

The doc says for GridLayout that:
[...] It is similar to the widget-based QGridLayout. All visible children of the GridLayout element will belong to the layout. [...].
So what you are seeing is a direct consequence of the implementation approach followed by developers. Indeed a change in visibility triggers Items repositioning, as can be seen in this code path.
Instead of considering visible property you can use opacity property: the non-opaque Items are taken in account by the layout, resulting in the expected visible behaviour. See for instance this simple example:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
Window {
visible: true
height: 400; width: 400
GridLayout {
anchors.fill: parent
id: gridLayout
rows: 3
columns: 3
Repeater {
id: rep
model: 9
Rectangle {
color: "black"
Layout.preferredWidth: 100
Layout.preferredHeight: 100
Layout.alignment: Qt.AlignCenter
opacity: index === rep.count - 1
}
}
}
}
Mind that non-opaque Items are still rendered, differently from invisible ones, with a varying degree of impact over performances, depending on your actual use case.

Related

Looking for alternate function to QML ListView's itemAtIndex due to version conflict

I'm using Qt 5.12, so I can't access ListView's itemAtIndex which was introduced in Qt 5.13.
I can't upgrade Qt due to my project/platform related restrictions. Is there a way to find the item at a given index for ListView with the Qt versions prior to 5.13?
Otherwise, is there a way to get mouse positions of an item based on index?
I'm having a listview with adjacent items having different width(alternate items have same width). I'm trying to access listview's item which is of less width compared to the adjacent item. The space between two items in the above picture is also an item which is marked as dummy. I'm able to get the index of each item (both actual & dummy), but the x position I get seems to be incorrect as the rectangle cursor is not getting placed in the intended item's position.
Please suggest alternatives that gives the similar functionality as itemAtIndex. Thanks.
In the following example, I declare a MouseArea in each delegate. So, once the mouse hovers over that delegate, we trigger MouseArea.onEntered and can know which item, because that delegate will have the corresponding index value:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
background: Rectangle { color: "#848895" }
ColumnLayout {
anchors.fill: parent
ListView {
id: listView
Layout.fillWidth: true
Layout.preferredHeight: 150
model: 20
orientation: ListView.Horizontal
delegate: MyDelegate { }
ScrollBar.horizontal: ScrollBar {
height: 20
policy: ScrollBar.AlwaysOn
}
highlight: Item {
z: 2
Rectangle {
width: 10
height: parent.height
color: "lightsteelblue"
border.color: "black"
}
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Frame {
anchors.centerIn: parent
background: Rectangle { }
Text {
text: qsTr("ListView.currentIndex = %1").arg(listView.currentIndex)
}
}
}
}
}
// MyDelegate.qml
import QtQuick
import QtQuick.Controls
Rectangle {
property ListView listView: ListView.view
width: 120
height: listView.height - 20
implicitWidth: width
implicitHeight: height
color: "transparent"
Rectangle {
border.color: "grey"
color: "white"
y: 20
height: parent.height - y * 2
width: parent.width
Text {
anchors.centerIn: parent
text: qsTr("Item %1").arg(modelData + 1)
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: listView.currentIndex = index
}
}
You can Try it Online!

Why my highlight item quick show and disapper?

I write a simple ListView and want to highlight the item when keyboard arrow key pressed.
The program look like well but the highlight function work strange,it quickly show and the disapper in my eye.This not the effect I wanted,I want it always show highlight color when the current item is highlight.
import QtQuick 2.15
import QtQuick.Window 2.15
Rectangle {
width: 400
height: 400
Component {
id: nameDelegate
Rectangle {
width: ListView.view.width
height: 30
Text {
anchors.centerIn: parent
text: index
font.pixelSize: 14
}
}
}
ListView {
anchors.fill: parent
spacing: 5
focus: true
model: 10
delegate: nameDelegate
highlight: Rectangle {
width: ListView.view.width
height: ListView.view.currentItem.height
color: "lightGray"
}
}
}
Add New Info
If I change delegate item(rectangle) to below
Rectangle {
width: ListView.view.width
height: 30
color: "#ada"
Text {
anchors.centerIn: parent
text: index
font.pixelSize: 14
}
}
And I want to the highligh item show lightgray when arrow key press, how can I do this?
It's because of stacking order.
The highlight's default z value is 0. Each delegate has z value of 1, so by default the highlight is behind each delegate.
Your delegate has a white Rectangle as its background, so the highlight will not be visible.
You can either remove the white background from the delegate (e.g. just use a plain Item or set the color of the rectangle to be transparent) or increase the z value of the highlight. The latter will result in the text not being visible, though, so you would have to rethink how the highlight could look. For example, you could make it an underline instead of a solid block of colour:
ListView {
anchors.fill: parent
spacing: 5
focus: true
model: 10
delegate: nameDelegate
highlight: Item {
z: 2
Rectangle {
width: parent.width
height: 1
y: parent.height - height
color: "lightGray"
}
}
}

How to increase height of Rectangle according to text in QML

I am not able to increase height of Rectangle (or RowLayout) wrapped around Text item that could dynamically change (chat message for example).
I tried bunch of approaches (Text.paintedHeight, childrenRect ...) but everything looks funky when text is wrapped.
My goal is display chat messages, stretch them according their wrapped text height.
Thanks for any input.
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 900
height: 500
ColumnLayout {
width: parent.width
spacing: 2
RowLayout {
id: rowLayout
spacing: 3
Rectangle {
height: 50
width: 50
color: "red"
}
Rectangle {
id: rectangle
width: 50
color: "green"
Layout.fillHeight: true
Layout.fillWidth: true
Text {
id: element
text: "If the GridLayout is resized, all items in the layout will be rearranged. It is similar to the widget-based QGridLayout. All visible children of the GridLayout element will belong to the layout. If you want a layout with just one row or one column, you can use the RowLayout or ColumnLayout. These offer a bit more convenient API, and improve readability.\n\nBy default items will be arranged according to the flow property. The default value of the flow property is GridLayout.LeftToRight.\n\nIf the columns property is specified, it will be treated as a maximum limit of how many columns the layout can have, before the auto-positioning wraps back to the beginning of the next row. The columns property is only used when flow is GridLayout.LeftToRight."
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
clip: false
font.pixelSize: 12
}
}
}
}
}
You have to specify the implicitHeight and implicitWidth for Rectangle (and Item for that matter).
Rectangle {
id: rectangle
width: 50
color: "green"
Layout.fillHeight: true
Layout.fillWidth: true
implicitWidth: element.implicitWidth
implicitHeight: element.implicitHeight
Text {
id: element
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
clip: false
font.pixelSize: 12
}
}
Please note that your current setup with anchors.margins is slightly conflicting here, since that is not counted in the implicitHeight/Width, so I left them out.
Another option would be to set the background for a Label (from QtQuick.Controls) to your desired Rectangle, that will then be stretched properly:
Label {
leftPadding: 10
rightPadding: 10
...
background: Rectangle {
color: "green"
}
}
In my opinion this would give you easier control about the position of your text.

TextArea problematic background QML QT

Trying different code combinations and partially solving my problem I came across a behavior that I can not quite explain. So to the point, When I create a simple TextArea without Scrollview it looks like this:
RowLayout {
id: rowLayout
Rectangle{
height: 50
width: 295
TextArea {
id: textArea
text: (" message...")
wrapMode: Text.WrapAnywhere
anchors.fill: parent
}
}
Text area creates a default background. And now I want to do TextArea with ScrollView ALSO with the default TextArea background but it comes out something like that :
RowLayout {
id: rowLayout
Rectangle{
height: 50
width: 295
ScrollView {
id: scrollView1
anchors.fill: parent
TextArea {
id: textArea
text: (" message...")
wrapMode: Text.WrapAnywhere
}
}
}
The only chance to set the default TextArea background is set implicitHeight,implicitWidth but then after entering the text into a TextArea until the scrollbar appears, the background extends over the entire length by going behind the other components like this :
RowLayout {
id: rowLayout
Rectangle{
//color: "#00000000"
height: 50
width: 295
ScrollView {
id: scrollView1
anchors.fill: parent
TextArea {
id: textArea
text: (" message...")
wrapMode: Text.WrapAnywhere
implicitHeight: 50
implicitWidth: 295
}
}
}
So the only thing I want is a scrollable textarea but with this black default background and NOT my background which I can do with rectangle.
Can anyone take a look?
Thank you :)
I tried do my best. Check the example below, hope it will help =)
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 400
height: 400
RowLayout {
width: 295
height: 50
anchors.centerIn: parent
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
background: Rectangle { color: "black" }
TextArea {
id: messageField
placeholderText: qsTr("message...")
color: "white"
wrapMode: TextArea.WrapAnywhere
}
}
}
}
Result:

Why does anchors.fill does not work in a QML ListView's delegate's subviews, and what is a nice solution?

I encountered this:
ListView {
id: listView
model: ["Lorem","Ipsum"]
delegate: Item {
height: 20
Text {
z: 2
text: modelData
anchors.fill: parent
}
Rectangle {
z: 1
color: "red"
// this does not work:
anchors.fill: parent
// this works, but I have mixed feelings about it:
// height: 20; width: listView.width
}
}
}
So, apparently, anchors do not work in a delegate's subitem (in this case, Rectangle is not displayed at all). I would like to understand the mechanism behind this. Also, I'd like to ask what is the preferred way to deal with this situation?
Thank You!
Item has an implicitWidth and implicitHeight of zero, so making your Rectangle and Text fill it will result in them having no size as well.
There are two things wrong with your code:
The ListView has no width or height specified.
Your delegate has no width specified.
Here's one way of doing it correctly:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
width: 300
height: 300
visible: true
ListView {
id: listView
anchors.fill: parent
model: ["Lorem","Ipsum"]
delegate: Item {
width: listView.width
height: textItem.implicitHeight
Text {
id: textItem
z: 2
text: modelData
width: parent.width
}
Rectangle {
z: 1
color: "red"
anchors.fill: parent
}
}
}
}
The documentation of ListView has more information.

Resources