How to align items in a ListView in QtQuick - qt

I have the following horizontal list:
BulletsListDelegate.qml
import QtQuick 2.0
Rectangle {
width: 8
height: 8
color: "#808080"
radius: width * 0.5
}
main.qml
import QtQuick 2.0
Item {
width: 256
height: 256
ListModel {
id: bulletsListModel
ListElement {
a: 'example'
}
ListElement {
a: 'example'
}
...
}
ListView {
id: bulletsList
spacing: 8
orientation: ListView.Horizontal
delegate: BulletsListDelegate {}
model: bulletsListModel
anchors.bottom: parent.bottom
width: parent.width
}
}
And the elements are shown like this (they are the grey bullets)
I want them to show in the horizontal center of the black box above them (its parent).
Is there any form of centralize or justify the items of the list?

So, if I understand your question correctly, you want to have alignment for instances of your items in a ListView. Using a ListView, that is not so easy to achieve. If you have an uneven number of items, you can do it by using preferredHighlightBegin and preferredHighlightEnd to have a 1-item sized region in the center of your ListView, and then setting hightlightRangeMode to ListView.StrictlyEnforceRange. You can set the currentIndex to point to index so that the middle item will be considered current. That puts it within the range you defined, and thus in the center. That does not work when you have an even number of items though, so it's a hack with limited value.
My question is: do the items have to be positioned using a ListView? It looks like you don't actually need much of the functionality of the ListView at all? If you don't need the other features from ListView (like scrolling), you can just use a Repeater instead. That allows you to simply put the items in a Row positioner, which you can width of count*(delegateWidth+spacing)-spacing and a height equal to your delegate height. Then, you can use acnhors to position the Row centered to whatever you like.

André's answer suggested me to use Repeater and Rows instead of ListView, and it completely solved my problem. But... didn't find a way to align an actual ListView yet.
Row {
spacing: 8
Repeater {
id: bulletsRepeater
model: 5
BulletsDelegate { }
}
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}

Related

QML Listview space items to fill width

I have a ListView (horizontal orientation) in my qml containing some fixed-size elements. I want items to be spaced out to fill the entiew width of ListView element. So if there are less elements I want them to be spaced out more. Basically what I need is exactly like Layout.fillWidth = true property of RowLayout but for ListView.
I can count how many items I have, then subtract total items width from ListView width, divide by items count and assign the spacing but it seems too silly to do.
Is there a way to do this automatically like in RowLayout?
Or maybe I need to use something different from ListView for this? Something like RowLayout but that I can assign my list data model to?
You can accomplish what you want with a ListView, you just need to adjust the spacing dynamically based on how many delegates you have. This example will break down if your delegates are differently-sized (as this is based only on the width of the first delegate), or if the delegates cumulatively exceed the width of the ListView.
ListView {
width: 500
orientation: Qt.Horizontal
model: 6
spacing: {
if (count > 0) {
return (width - (itemAtIndex(0).width * count))/(count - 1)
} else {
return 0
}
}
delegate: Rectangle {
implicitHeight: 50
implicitWidth: 50
color: "red"
border.width: 1
}
}
ListView may not be the most appropriate container for this task. I say this because it has a built in ScrollView and other behaviors that it sounds like you don't need. If all you need is a simple row of a few identically-sized delegates, I agree with scopchanov and believe that a Repeater inside a RowLayout would be the best option. Here is a simple example:
RowLayout {
width: 500
Repeater {
model: 6
delegate: Rectangle {
implicitHeight: 50
implicitWidth: 50
color: "tomato"
border.width: 1
Layout.alignment: Qt.AlignHCenter // must be set to align the rectangles within their empty space
}
}
}
You may notice that this introduces gaps to the left and right, if these gaps are unacceptable, you may need to set the spacing on the RowLayout in the same manner as the ListView example instead.

QML: What does the "x" property exactly do and what's the difference with anchors.leftMargin/rightMargin in a ListView?

I tried to add a margin to a ListView element using anchors.leftMargin expecting it would create a margin between the screen border and the beginning of the list, but it didn't work at all. Using x instead solved the problem. Here is the code:
ListView {
id: list
width: parent.width - sideMargin
x: sideMargin //works
anchors.leftMargin: sideMargin //doesn't work
orientation: ListView.Horizontal
focus: true
spacing: 16
//...
}
So now I am wondering when to use these properties, because reading the docs is not enough for me to understand when to use one or the other.
Items in QML/QtQuick can be positioned and sized in 3 different ways:
Freely using the x and y properties for position and the width and height properties for the size.
See: https://doc.qt.io/qt-5/qml-qtquick-item.html#x-prop for more information.
ListView {
id: list
width: parent.width - sideMargin
x: sideMargin
y: topMargin
}
Using Layouts, or more generally containers, such as ColumnLayout. All the work is done by the layout and you don't have to do anything, but you can still provide tips to the container.
Using anchors. This is done through the anchors properties of each Item. This works by attaching (anchoring) Items against each other.
ListView {
id: list
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: sideMargin
}
Note: Do not mix these 3 ways on a single Item as you can create conflicts or have unexpected results. In your case you are using method 3 for setting the margin without setting a position and method 1 for setting the width and thus it does not work.

Hide an item (delegate) inside a ListView QML

Is there a way to hide a particular item on some event in a ListView?
So far I can do it by setting visible to false and height to zero of a delegate.
But If i have spacing in a listView set to 2 for example it appears that this solution is broken.
I think the proper way is to use a proxy model that filters out the elements that should not be displayed.
You can use a QSortFilterProxyModel or implement your own QAbstractProxyModel.
With that it is even possible to animate the removal and addition of the elements.
Or use SortFilterProxyModel if you don't wanna touch C++ and performance is not a problem
A hack around this could be to set the spacing of the ListView to 0 and implement it in the delegate itself. Something like this:
ListView{
id: listView
spacing: 0
delegate: Item{
id: itemDelegate
width: parent.width; height: spacingRect.height + actualDelegate.height
Item {id: actualDelegate;} // your actual delegate
Rectangle{ id: spacingRect; height: 2; width: parent.width; color: "transparent"; anchors.top: actualDelegate.bottom}
}
}
In this way when you hide the delegate the spacing will also be hidden

Center QML ListView highlighted item

In the picture Test, Test 1 and Test 2 are in the ListView. In this case Test element is highlighted. How can I modify view behavior to ensure that current (highlighted) item stays always in the middle of the list? What I want to achieve is represented in the following picture:
You just need highlightRangeMode with preferredHighlightBegin and preferredHighlightEnd. From the documentation:
These properties affect the position of the current item when the list is scrolled. For example, if the currently selected item should stay in the middle of the list when the view is scrolled, set the preferredHighlightBegin and preferredHighlightEnd values to the top and bottom coordinates of where the middle item would be. If the currentItem is changed programmatically, the list will automatically scroll so that the current item is in the middle of the view. Furthermore, the behavior of the current item index will occur whether or not a highlight exists.
Here is a full example of an horizontal ListView with the current item positioned at the center.
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
width: 300
height: 150
visible: true
ListView {
anchors.fill: parent
spacing: 5
model: 20
delegate:
Rectangle {
width: 30
color: ListView.view.currentIndex === index ? "red" : "steelblue"
height: ListView.view.height
Text {
anchors.centerIn: parent
text: index
font.pixelSize: 20
}
}
orientation: Qt.Horizontal
preferredHighlightBegin: 150 - 15
preferredHighlightEnd: 150 + 15
highlightRangeMode: ListView.StrictlyEnforceRange
}
}
You could have a look at ListView's positionViewAtIndex method and see if that helps.

How to correctly change the row height of a TableView?

Window {
id: uninstallWindow
width: 640
height: 480
property variant pluginData;
TableView {
id:_pluginTable
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 43
anchors.top: parent.top
anchors.topMargin: 0
model: pluginData
itemDelegate: Text {
text: modelData
font.pixelSize: 24
}
TableViewColumn {
}
}
}
It's taken me hours just to get this far, and I feel like this should be a relatively simple operation, so why is it so hard? As you can see I change the font size of the items in the table because they were too small by default. This simply caused them to get clipped by the non-changing row size. I've tried
Setting a rowDelegate object (but this causes loss of all other styling info that is there by default like background, selection color, etc and I don't know how to specify it otherwise)
Setting a custom model object based on QAbstractListModel / QAbstractTableModel (for some reason only known to Qt, the "data" function was never ever called...)
Setting a custom item delegate (it seems that the height is no longer controlled from this object though)
What hoops do I need to jump through to get the rows to change their size?
As the Asker already wrote, custom row height can be achieved using the rowDelegate, but this discards the default style. The default style can be restored using the SystemPalette.
rowDelegate: Rectangle {
height: 30
SystemPalette {
id: myPalette;
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate?myPalette.alternateBase:myPalette.base
return styleData.selected?myPalette.highlight:baseColor
}
}
This restores the default background color of the rows (including alternating the row colors when desired) and the color of the selected rows, which seems to be all that is needed.
The following just worked like a charm for me in Qt 5.10:
rowDelegate: Item { height: 30 }
I do the actual styling (fonts/colors) in itemDelegate (and in headerDelegate) and provide content by TableViewColumns (with and without delegates of their own).
To change the row height you need to use rowDelegate. For example:
rowDelegate: Rectangle{
width: childrenRect.width
height: 40
}
To change tableview height you can use Layout.preferredHeight. For example:
Layout.preferredHeight: 300

Resources