Is it possible to show only certain indexes or a range of indexes in QML listviews?
I have a listmodel that has a bunch of info that I am reusing. Would it be possible to have a list showing, for example, only indices 5 to 8?
Is it possible to show only certain indexes or a range of indexes in QML listviews?
I have a listmodel that has a bunch of info that I am reusing. Would it be possible to have a list showing, for example, only indices 5 to 8?
It would be interesting to present a pure QML approach to the problem. This is not the shorted path, for sure, but it is a solution.
The approach is based on the DelegateModel
available in the models
QML module. It reads in the documentation:
The DelegateModel type encapsulates a model and the delegate that will be instantiated for items in the model.
It is usually not necessary to create a DelegateModel. However, it can be useful for manipulating and accessing the modelIndex when a QAbstractItemModel subclass is used as the model. Also, DelegateModel is used together with Package to provide delegates to multiple views, and with DelegateModelGroup to sort and filter delegate items.
DelegateModel
is really a powerful type with a lot of functionalities (see the linked documentation for details). Two key properties of DelegateModel
are groups
and filterOnGroup
. The former is basically a list of DelegateModelGroup
which defines the items to be filtered or not. The latter is used to apply a specific filter, i.e. choose a specific DelegateModelGroup
contained in groups
, by simply setting the property to the name of the chosen group.
Note that referring to VisualDataModel
or DelegateModel
is the same since the first is provided for compatibility reasons (the same applies to VisualDataGroup
w.r.t. DelegateModelGroup
).
Summing up, it is possible to filter a model in full QML in this way:
model
as a source of filtered modelsmodel
to a VisualDataModel
/DelegateModel
VisualDataGroup
/DelegateModelGroup
(or more than one) - includeByDefault
set to false
to avoid automatic addition of all items from the original model filterOnGroup
to the chosen groupVisualDataModel
modelIn the next example, for simplicity, I just populate the group once, during the Component.onCompleted
event handler. As said, policies should be chosen and that's depends on the specific use case.
In the example only the items with key
role equal to 0
are added to the group key0
which is the one shown in the ListView
. The checklist described above is highlighted in the code.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
title: qsTr("DelegateModel test")
width: 200
height: 350
visible: true
ListView {
id: displayListView
anchors.fill: parent
spacing: 5
//
model: displayDelegateModel // 6
}
ListModel { // 1
id: myModel
ListElement { vis: "One"; key: 0; }
ListElement { vis: "two"; key: 1; }
ListElement { vis: "Three"; key: 0; }
ListElement { vis: "Four"; key: 0; }
ListElement { vis: "Five"; key: 1; }
ListElement { vis: "Six"; key: 1; }
ListElement { vis: "Seven"; key: 0; }
}
VisualDataModel {
id: displayDelegateModel
delegate: Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 25
color: "steelblue"
Text {
text: vis
anchors.centerIn: parent
font.bold: true
font.pixelSize: 20
}
}
model: myModel // 2
groups: [
VisualDataGroup { // 3
includeByDefault: false // NECESSARY TO AVOID AUTOADDITION
name: "key0"
}
]
filterOnGroup: "key0" // 5
Component.onCompleted: { // 4
var rowCount = myModel.count;
items.remove(0,rowCount);
for( var i = 0;i < rowCount;i++ ) {
var entry = myModel.get(i);
if(entry.key == 0) {
items.insert(entry, "key0");
}
}
}
}
}
Yes, it is possible. You need to override QSortFilterProxyModel::filterAcceptRow
method.
MyFilterModel::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const
{
if ( source_row > 5 && source_row < 8 )
return true;
return false;
}
//...
MyFilterModel *filter = new MyFilterModel();
filter->setSourceMoldel( yourSourceModel );
view->setModel( filter );
You could accomplish that by setting the delegate visibility to false on certain conditions:
Grid {
anchors.fill: parent
rows: 4
columns: 5
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
visible: index >= 5 && index <= 8 // show only certain indices
Text {
anchors.centerIn: parent
text: index
}
}
}
}
It will have some overhead of creating hidden items in memory thou, so not optimal if you deal with very large models and showing only small portions of them.
visible: currentPage == 1 ? index < 6 : index >= 6
where currentPage
is a root property. No caveats. Just worked. –
Weis This is another answer based on DelegateModel
that:
"all"
and "visible"
role
, from
, and to
properties (for property binding)update()
methodupdate()
is called, the "all" group is rescanned and only matching/filtered records are placed in the "visible" groupTo demonstrate this I put 8 animals into a ListModel
. I define a RangeSlider
for controlling the from
and to
parameters that will control which elements I want to see in the DelegateModel
.:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
ListModel {
id: animals
ListElement { aid: 1; animal: "Aardvark" }
ListElement { aid: 2; animal: "Bear" }
ListElement { aid: 3; animal: "Cat" }
ListElement { aid: 4; animal: "Dog" }
ListElement { aid: 5; animal: "Eagle" }
ListElement { aid: 6; animal: "Fruitbat" }
ListElement { aid: 7; animal: "Goat" }
ListElement { aid: 8; animal: "Hedgehog" }
}
ColumnLayout {
anchors.fill: parent
Label { text: qsTr("Select Range") }
RangeSlider { id: range; from: 1; to: 8; first.value: 3; second.value: 8 }
Label { text: qsTr("Animals %1 .. %2").arg(range.first.value).arg(range.second.value) }
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: DelegateModel {
model: animals
property string role: "aid"
property real from: range.first.value
property real to: range.second.value
onRoleChanged: Qt.callLater(update)
onFromChanged: Qt.callLater(update)
onToChanged: Qt.callLater(update)
delegate: Label { text: `${aid} ${animal}` }
groups: [
DelegateModelGroup { id: all; name: "all"; includeByDefault: true },
DelegateModelGroup { name: "visible" }
]
filterOnGroup: "visible"
function update() {
all.setGroups(0, all.count, [ "all" ] );
for (let i = 0; i < all.count; i++) {
const item = all.get(i).model;
const visible = item[role] >= from && item[role] <= to;
if (visible) all.setGroups(i, 1, [ "all", "visible" ]);
}
}
Component.onCompleted: Qt.callLater(update)
}
}
}
}
You can Try it Online!
© 2022 - 2024 — McMap. All rights reserved.