Skip to content

Instantly share code, notes, and snippets.

@mottosso
Last active August 11, 2022 14:24
Show Gist options
  • Save mottosso/50655da4018ecbe0f8c2 to your computer and use it in GitHub Desktop.
Save mottosso/50655da4018ecbe0f8c2 to your computer and use it in GitHub Desktop.
Filtering in QML ListView

Filtering in QML ListView

image

This example illustrates how QSortFilterProxyModel and QAbstractListModel can be used to display a list of filterable items in QML and Python.

Usage

Run filtering.py; it will load filtering.qml which will need to be located in the same directory.

import sys
from PyQt5 import QtCore, QtGui, QtQuick
class Model(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(Model, self).__init__(parent)
self.items = [
{"name": "Item1"},
{"name": "Item2"},
{"name": "Item3"},
{"name": "Item4"},
{"name": "Item5"},
{"name": "Item6"},
{"name": "Item12"},
{"name": "Item13"},
{"name": "Item14"},
]
self.roles = {
QtCore.Qt.UserRole + 1: "name"
}
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def data(self, index, role=QtCore.Qt.DisplayRole):
try:
item = self.items[index.row()]
except IndexError:
return QtCore.QVariant()
if role in self.roles:
return item.get(self.roles[role], QtCore.QVariant())
return QtCore.QVariant()
def roleNames(self):
return self.roles
app = QtGui.QGuiApplication(sys.argv)
view = QtQuick.QQuickView()
model = Model()
proxy = QtCore.QSortFilterProxyModel()
proxy.setSourceModel(model)
proxy.setFilterRole(model.roles.keys()[0])
proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
engine = view.engine()
context = engine.rootContext()
context.setContextProperty("qmodel", proxy)
view.setSource(QtCore.QUrl("filtering.qml"))
view.setResizeMode(view.SizeRootObjectToView)
view.show()
app.exec_()
import QtQuick 2.3
import QtQuick.Controls 1.3
Rectangle {
width: 400
height: 500
color: "brown"
TextField {
id: edit
placeholderText: "Filter.."
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
onTextChanged: qmodel.setFilterFixedString(text)
}
Rectangle {
color: "white"
radius: 2
anchors.top: edit.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 10
ListView {
id: listView
clip: true
model: qmodel
spacing: 10
anchors.fill: parent
anchors.margins: 5
delegate: Text {
text: name
}
}
}
}
@sturmf
Copy link

sturmf commented May 10, 2016

Hi, how do you access the underlying item in case a row is activated? I get the row number in that case, but how do I map that back to the correct item?

@mottosso
Copy link
Author

Hi @sturmf, sorry for the delay, I'm didn't receive any notification!

To map the row number to the item, just use it as an index to that list.

model.items[row]

@beac0n
Copy link

beac0n commented Apr 29, 2021

Very nice example. Thank you!
One small update: I had to set the object ownership for the proxy, or I would get a segfault:

engine.setObjectOwnership(proxy, QQmlApplicationEngine.JavaScriptOwnership)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment