need ideas on styling a ListView
-
wrote on 12 Dec 2022, 16:53 last edited by
@JoeCFD that's not quite what I want. What I think I need is:
- a Rectangle with the color I would normally use in my delegate. This would have the rounded corners. (z: 1)
- another Rectangle with height = (first rectangle - (firstRectangleRadius * 2), vertically centered. This Rectangle would be colored to represent the dividers. (z: 2)
- my ListView elements, with the same color as the first Rectangle. (z: 3)
But I don't know how to code this. When I try to introduce the first Rectangle, it hides my list, even if I use the z values.
-
@JoeCFD that's not quite what I want. What I think I need is:
- a Rectangle with the color I would normally use in my delegate. This would have the rounded corners. (z: 1)
- another Rectangle with height = (first rectangle - (firstRectangleRadius * 2), vertically centered. This Rectangle would be colored to represent the dividers. (z: 2)
- my ListView elements, with the same color as the first Rectangle. (z: 3)
But I don't know how to code this. When I try to introduce the first Rectangle, it hides my list, even if I use the z values.
wrote on 12 Dec 2022, 17:26 last edited by JoeCFD 12 Dec 2022, 17:30@mzimmers I do not think that is a good idea. Delegates are made for rows. Your round corners are global settings.
Normally you use alternative colors in listview(just like in tables) to display different rows. Pretty much standard practice. Therefore, no dividers are needed. -
@mzimmers I do not think that is a good idea. Delegates are made for rows. Your round corners are global settings.
Normally you use alternative colors in listview(just like in tables) to display different rows. Pretty much standard practice. Therefore, no dividers are needed. -
wrote on 12 Dec 2022, 22:46 last edited by
import QtQuick 2.15 import QtQuick.Window 2.15 Window { width: 640 height: 480 visible: true Rectangle { id: background anchors.fill: parent color: "blue" } ListView { model: 10 anchors.centerIn: parent height: parent.height / 2 width: parent.width / 2 spacing: 2 boundsBehavior: Flickable.StopAtBounds delegate: Rectangle { height: 10 width: ListView.view.width Text { text: index anchors.centerIn: parent } } Rectangle { anchors.centerIn: parent.contentItem border.width: 15 border.color: background.color width: parent.contentItem.width + border.width * 2 height: parent.contentItem.height + border.width * 2 radius: border.width * 2 color: "transparent" } } }
-
import QtQuick 2.15 import QtQuick.Window 2.15 Window { width: 640 height: 480 visible: true Rectangle { id: background anchors.fill: parent color: "blue" } ListView { model: 10 anchors.centerIn: parent height: parent.height / 2 width: parent.width / 2 spacing: 2 boundsBehavior: Flickable.StopAtBounds delegate: Rectangle { height: 10 width: ListView.view.width Text { text: index anchors.centerIn: parent } } Rectangle { anchors.centerIn: parent.contentItem border.width: 15 border.color: background.color width: parent.contentItem.width + border.width * 2 height: parent.contentItem.height + border.width * 2 radius: border.width * 2 color: "transparent" } } }
-
@jeremy_k that's getting really close to what I need. Now, regarding the background rectangle, how best to set its height to the effective height of the ListView instead of filling the Window?
Thanks!
wrote on 13 Dec 2022, 01:52 last edited byListView { id: listView model: 10 anchors.centerIn: parent height: parent.height / 2 width: parent.width / 2 spacing: 2 boundsBehavior: Flickable.StopAtBounds delegate: Rectangle { height: 10 width: ListView.view.width } Rectangle { anchors.fill: overlay color: "blue" z: -1 } Rectangle { id: overlay anchors.centerIn: parent.contentItem border.width: 15 border.color: "blue" width: parent.contentItem.width + border.width * 2 height: parent.contentItem.height + border.width * 2 radius: border.width * 2 color: "transparent" } }
-
@mzimmers I do not think that is a good idea. Delegates are made for rows. Your round corners are global settings.
Normally you use alternative colors in listview(just like in tables) to display different rows. Pretty much standard practice. Therefore, no dividers are needed.wrote on 13 Dec 2022, 04:28 last edited by@JoeCFD said in need ideas on styling a ListView:
@mzimmers I do not think that is a good idea. Delegates are made for rows. Your round corners are global settings.
DelegateChooser, explicit use of a Loader, or hiding/showing items that are always present are all viable techniques.
Going this route, I might do something like:
ListView { delegate: Rectangle { id: d Image { source: d.index == 0 ? topCorner : d.index == (d.ListView.view.count - 1) ? bottomCorner : undefined } }
Normally you use alternative colors in listview(just like in tables) to display different rows. Pretty much standard practice. Therefore, no dividers are needed.
That's a common design choice, but certainly not universal. Wanting a different appearance isn't unreasonable.
-
wrote on 13 Dec 2022, 18:15 last edited by
I think I got it (sorry for the lengthy code include, but I wanted to show everything):
// Roundlist.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts Item { height: parent.height width: parent.width Rectangle { id: rect1 property real rectRadius: 5.0 property real rowHeight: 60.0 property real rowSpacing: 3.0 height: activityView.height + (rectRadius * 2) width: parent.width radius: rect1.rectRadius anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } color: 'white' Rectangle { id: rect2 height: activityView.height width: rect1.width anchors.verticalCenter: rect1.verticalCenter color: mainWindow.color ListModel { id: activityModel ListElement { text: "aaa" } ListElement { text: "bbb" } ListElement { text: "ccc" } ListElement { text: "ddd" } ListElement { text: "eee" } } Component { id: activityDelegate Rectangle { height: rect1.rowHeight width: rect1.width color: rect1.color Text { text: model.text anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } } } } ListView { id: activityView implicitHeight: contentItem.childrenRect.height width: rect1.width spacing: rect1.rowSpacing clip: true model: activityModel delegate: activityDelegate } } } }
It works by itself, though I'm having problem embedding it in a ColumnLayout - instead of appearing inline, it overlays the other items. It should look something like this:
But it comes out like this (please ignore the different text in the rows):
Here's how I'm trying to use it (heavily edited):Flickable { id: flickable Layout.fillHeight: true Layout.fillWidth: true clip: true contentHeight: pumpStuff.height ColumnLayout { id: pumpStuff height: parent.height width: flickable.width - (scroller.width * 2) RowLayout { id: actions } Text { id: parameters } Roundlist {} RowLayout { id: activities } } ScrollBar.vertical: ScrollBar { id: scroller policy: ScrollBar.AlwaysOn//AsNeeded } }
Any idea why this is happening?
Thanks...
-
I think I got it (sorry for the lengthy code include, but I wanted to show everything):
// Roundlist.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts Item { height: parent.height width: parent.width Rectangle { id: rect1 property real rectRadius: 5.0 property real rowHeight: 60.0 property real rowSpacing: 3.0 height: activityView.height + (rectRadius * 2) width: parent.width radius: rect1.rectRadius anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } color: 'white' Rectangle { id: rect2 height: activityView.height width: rect1.width anchors.verticalCenter: rect1.verticalCenter color: mainWindow.color ListModel { id: activityModel ListElement { text: "aaa" } ListElement { text: "bbb" } ListElement { text: "ccc" } ListElement { text: "ddd" } ListElement { text: "eee" } } Component { id: activityDelegate Rectangle { height: rect1.rowHeight width: rect1.width color: rect1.color Text { text: model.text anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } } } } ListView { id: activityView implicitHeight: contentItem.childrenRect.height width: rect1.width spacing: rect1.rowSpacing clip: true model: activityModel delegate: activityDelegate } } } }
It works by itself, though I'm having problem embedding it in a ColumnLayout - instead of appearing inline, it overlays the other items. It should look something like this:
But it comes out like this (please ignore the different text in the rows):
Here's how I'm trying to use it (heavily edited):Flickable { id: flickable Layout.fillHeight: true Layout.fillWidth: true clip: true contentHeight: pumpStuff.height ColumnLayout { id: pumpStuff height: parent.height width: flickable.width - (scroller.width * 2) RowLayout { id: actions } Text { id: parameters } Roundlist {} RowLayout { id: activities } } ScrollBar.vertical: ScrollBar { id: scroller policy: ScrollBar.AlwaysOn//AsNeeded } }
Any idea why this is happening?
Thanks...
wrote on 13 Dec 2022, 18:36 last edited byUnexpected overlapping is frequently a lack of sizing in the outermost item in a component. Eg:
Item { Rectangle { width: 100; height: 100 } }
-
I think I got it (sorry for the lengthy code include, but I wanted to show everything):
// Roundlist.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts Item { height: parent.height width: parent.width Rectangle { id: rect1 property real rectRadius: 5.0 property real rowHeight: 60.0 property real rowSpacing: 3.0 height: activityView.height + (rectRadius * 2) width: parent.width radius: rect1.rectRadius anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } color: 'white' Rectangle { id: rect2 height: activityView.height width: rect1.width anchors.verticalCenter: rect1.verticalCenter color: mainWindow.color ListModel { id: activityModel ListElement { text: "aaa" } ListElement { text: "bbb" } ListElement { text: "ccc" } ListElement { text: "ddd" } ListElement { text: "eee" } } Component { id: activityDelegate Rectangle { height: rect1.rowHeight width: rect1.width color: rect1.color Text { text: model.text anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } } } } ListView { id: activityView implicitHeight: contentItem.childrenRect.height width: rect1.width spacing: rect1.rowSpacing clip: true model: activityModel delegate: activityDelegate } } } }
It works by itself, though I'm having problem embedding it in a ColumnLayout - instead of appearing inline, it overlays the other items. It should look something like this:
But it comes out like this (please ignore the different text in the rows):
Here's how I'm trying to use it (heavily edited):Flickable { id: flickable Layout.fillHeight: true Layout.fillWidth: true clip: true contentHeight: pumpStuff.height ColumnLayout { id: pumpStuff height: parent.height width: flickable.width - (scroller.width * 2) RowLayout { id: actions } Text { id: parameters } Roundlist {} RowLayout { id: activities } } ScrollBar.vertical: ScrollBar { id: scroller policy: ScrollBar.AlwaysOn//AsNeeded } }
Any idea why this is happening?
Thanks...
wrote on 13 Dec 2022, 19:37 last edited by jeremy_k@mzimmers said in need ideas on styling a ListView:
I think I got it (sorry for the lengthy code include, but I wanted to show everything):
// Roundlist.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts Item { height: parent.height width: parent.width
As a style guide, never reference parent or anything outside of the component. Let the instantiator impose its constraints. Use implicitWidth and implicitHeight to specify reasonable defaults.
-
wrote on 13 Dec 2022, 20:16 last edited by
Apologies if this is answered, I only read the first 2 posts of this long topic.
I worked on something very similar just last month and the QML is really simple. (full).
delegate: Item { height: 80 clip: true Rectangle { // we always have the rounded circles, but if we should not see them, // we move them out of the clipped area. height: { var h = 80; if (index == 0) h += 20 if (index == MAX) // donno, bottom check. h += 20 return h; } radius: 20 y: index == 0 ? 0 : -20 } }
-
@mzimmers said in need ideas on styling a ListView:
I think I got it (sorry for the lengthy code include, but I wanted to show everything):
// Roundlist.qml import QtQuick import QtQuick.Controls import QtQuick.Layouts Item { height: parent.height width: parent.width
As a style guide, never reference parent or anything outside of the component. Let the instantiator impose its constraints. Use implicitWidth and implicitHeight to specify reasonable defaults.
wrote on 13 Dec 2022, 20:37 last edited by@jeremy_k said in need ideas on styling a ListView:
As a style guide, never reference parent or anything outside of the component. Let the instantiator impose its constraints. Use implicitWidth and implicitHeight to specify reasonable defaults.
Understood. How do you handle a case where the instantiator doesn't know the height, because (for example) there might be a variable number of rows? I'm hoping to make this reusable.
-
@jeremy_k said in need ideas on styling a ListView:
As a style guide, never reference parent or anything outside of the component. Let the instantiator impose its constraints. Use implicitWidth and implicitHeight to specify reasonable defaults.
Understood. How do you handle a case where the instantiator doesn't know the height, because (for example) there might be a variable number of rows? I'm hoping to make this reusable.
wrote on 13 Dec 2022, 23:21 last edited by jeremy_k@mzimmers said in need ideas on styling a ListView:
@jeremy_k said in need ideas on styling a ListView:
As a style guide, never reference parent or anything outside of the component. Let the instantiator impose its constraints. Use implicitWidth and implicitHeight to specify reasonable defaults.
Understood. How do you handle a case where the instantiator doesn't know the height, because (for example) there might be a variable number of rows? I'm hoping to make this reusable.
If width or height is not specified, an item's effective size will be determined by its implicitWidth or implicitHeight.
However, if an item is the child of a layout, the layout will determine the item's preferred size using its implicit size. In such a scenario, the explicit width or height will be ignored.
The default implicit size for most items is 0x0, however some items have an inherent implicit size which cannot be overridden, for example, Image and Text.
Setting the implicit size is useful for defining components that have a preferred size based on their content
-
@mzimmers said in need ideas on styling a ListView:
@jeremy_k said in need ideas on styling a ListView:
As a style guide, never reference parent or anything outside of the component. Let the instantiator impose its constraints. Use implicitWidth and implicitHeight to specify reasonable defaults.
Understood. How do you handle a case where the instantiator doesn't know the height, because (for example) there might be a variable number of rows? I'm hoping to make this reusable.
If width or height is not specified, an item's effective size will be determined by its implicitWidth or implicitHeight.
However, if an item is the child of a layout, the layout will determine the item's preferred size using its implicit size. In such a scenario, the explicit width or height will be ignored.
The default implicit size for most items is 0x0, however some items have an inherent implicit size which cannot be overridden, for example, Image and Text.
Setting the implicit size is useful for defining components that have a preferred size based on their content
wrote on 14 Dec 2022, 00:11 last edited by mzimmers@jeremy_k I see. So, this seems to work:
StackLayout { Home {} Equipment {} Rectangle { Layout.fillHeight: true Layout.fillWidth: true Roundlist { width: parent.width } } } // Roundlist.qml Item { implicitHeight: activityView.height + (rect1.rectRadius * 2) ...
And I can live with this, though it seems weird to set the height in once place, and the width in another. Is there a cleaner way to do this?
-
Apologies if this is answered, I only read the first 2 posts of this long topic.
I worked on something very similar just last month and the QML is really simple. (full).
delegate: Item { height: 80 clip: true Rectangle { // we always have the rounded circles, but if we should not see them, // we move them out of the clipped area. height: { var h = 80; if (index == 0) h += 20 if (index == MAX) // donno, bottom check. h += 20 return h; } radius: 20 y: index == 0 ? 0 : -20 } }
wrote on 14 Dec 2022, 00:23 last edited by@TomZ thanks for the reply. I think I prefer my implementation for my particular purposes, but I like elements of yours as well.
-
@jeremy_k I see. So, this seems to work:
StackLayout { Home {} Equipment {} Rectangle { Layout.fillHeight: true Layout.fillWidth: true Roundlist { width: parent.width } } } // Roundlist.qml Item { implicitHeight: activityView.height + (rect1.rectRadius * 2) ...
And I can live with this, though it seems weird to set the height in once place, and the width in another. Is there a cleaner way to do this?
wrote on 14 Dec 2022, 04:57 last edited by@mzimmers said in need ideas on styling a ListView:
And I can live with this, though it seems weird to set the height in once place, and the width in another. Is there a cleaner way to do this?
The component can set implicitWidth as well, and probably should. Otherwise you might end up with a 0-width item that renders correctly on its own, but is overlapped when used in a row layout of some form.
-
@mzimmers said in need ideas on styling a ListView:
And I can live with this, though it seems weird to set the height in once place, and the width in another. Is there a cleaner way to do this?
The component can set implicitWidth as well, and probably should. Otherwise you might end up with a 0-width item that renders correctly on its own, but is overlapped when used in a row layout of some form.
wrote on 14 Dec 2022, 05:00 last edited by@jeremy_k said in need ideas on styling a ListView:
The component can set implicitWidth as well, and probably should.
I'll do that -- just wondering whether there was any way to derive a value from the caller. But I guess the width value is just that, so...that's what I'll use. I'll just pick some value for the implicitWidth that hopefully will never get used.
Thanks for all the help...I think I'm done with this one.
-
wrote on 14 Dec 2022, 05:04 last edited by
FontMetrics could provide an implicitWidth value based on the model's data. I presume that Text does something similar.
-
wrote on 14 Dec 2022, 23:45 last edited by
For anyone who might be reading this for an answer to their own question, I looked at @TomZ 's solution, and realized that I had a bug in my delegate - my text centering wasn't taking the rounded corners effectively adding height to the top and bottom rows. I had to alter my delegate:
Component { id: activityDelegate Rectangle { height: { var h = rect1.rowHeight; if (index === 0 || index === (activityModel.count - 1)) h -= rect1.radius return h; } width: rect1.width color: rect1.color Text { text: model.parameter anchors { left: parent.left leftMargin: parent.height / 2 verticalCenter: parent.verticalCenter verticalCenterOffset: { var o = 0; if (index === 0) o -= (radius / 2) else if (index === (activityModel.count - 1)) o += (radius / 2) return o; } } font.pixelSize: 14 font.bold: true } Styledswitch { id: onOff visible: model.switchVisible anchors { right: parent.right rightMargin: parent.height / 2 verticalCenter: parent.verticalCenter } } } }
As always, if this doesn't look right, please let me know, and I'll fix it.
18/27