QML Model: Sort and filter the data on the fly
September 19, 2025 by SanthoshKumar | Comments
In most data-driven applications, sorting and filtering are very common and often necessary. Qt makes this easier by providing a built-in proxy model that can handle sorting and filtering without changing the original data. This model can be attached to a view and use it within the MVC framework to display the data. Developers can also extend its functionality by inheriting from QSortFilterProxyModel and overriding its filtering and sorting APIs, allowing for fully customised behaviour. This saves developers a lot of time since they donβt need to build these features from scratch, while still giving them the flexibility to customize as needed.
When it comes to Qt Quick, the modern UI development paradigm offers a declarative way for developers to quickly build dynamic, animated, and high-performance user interfaces. The simpler code with QML properties and JavaScript expressions also makes it readable and easier to understand. It is also to be noted that before 6.10, without the native QML proxy model, developers had to manually write sorting and filtering logic in C++, and this can result in redundant code when different sorters or filter models need to be used. The declarative way of having the model also allows developers to keep the source data manipulation part close to the UI and the actual business logic of handling the data with respect to the source model in C++.
With Qt 6.10, the QML SortFilterProxyModel is made available to sort and filter model data in the declarative way. The SortFilterProxyModel internally inherits from QAbstractProxyModel and similarly to the QSortFilterProxyModel the actual indices of the data in the source model is not altered. The source model can be set in the model attribute of the SortFilterProxyModel and the proxy model can be set in the model attribute of the views. The following example describes how to use the SortFilterProxyModel to filter the processes from the processModel that uses the CPU more than a user-specified percentage and then sort those by user-id.
SortFilterProxyModel {
id: sfpmProcessModel
model: processModel // Source model can be specified here
sorters: [
RoleSorter {
roleName: "uid"
}
]
filters: [
FunctionFilter {
component RoleData: QtObject { property int cpuUsage }
function filter(data: RoleData) : bool {
return (data.cpuUsage > parseInt(searchField.cpuUage))
}
}
]
}
TableView {
id: processView
anchors.fill: parent
model: sfpmProcessModel
clip: true
delegate: Rectangle {
implicitWidth: 200
implicitHeight: 40
border.color: "lightgray"
border.width: 1
Text {
anchors.centerIn: parent
text: display
}
}
}
To be noted, the thoughts and works were inspired and adapted from the existing project https://github.com/oKcerG/SortFilterProxyModel.
There are certain Filters and Sorters provided by default, which can be configured accordingly to get the desired result. The individual Filter and Sorters that are configured in the list can also be prioritized resulting in order of these operations applied to the data. For instance, it can be configured to filter the data with respect to their CPU usage and then further sort it with their process id.
SortFilterProxyModel {
id: sfpm
model: processModel
sorters: [
// First sort with process id and then further sort it with name
RoleSorter {
roleName: "cpu"
priority: 0 // Priority can be specified here
},
RoleSorter {
roleName: "pid"
priority: 1 // Priority can be specified here
},
RoleSorter {
roleName: "name"
priority: 2 // Priority can be specified here
},
RoleSorter {
roleName: "uid"
priority: 3 // Priority can be specified here
},
RoleSorter {
roleName: "state"
priority: 4 // Priority can be specified here
}
]
filters: [
FunctionFilter {
component RoleData: QtObject { property int cpuUsage }
function filter(data: RoleData) : bool {
return (data.cpuUsage > 0)
}
}
]
}
The data in the model can be filtered based on a specified column, allowing filters to be applied selectively rather than across all columns. This behavior is similar to the filterKeyColumn property and is designed to be configurable for individual filters. Note that the column index referenced here corresponds to the logical index, not the visual index.
SortFilterProxyModel {
id: sfpm
model: processModel
sorters: [
RoleSorter {
roleName: "name"
column: 1 // Column number can be specified here
}
]
filters: [
FunctionFilter {
component RoleData: QtObject { property int cpuUsage }
function filter(data: RoleData) : bool {
return (data.cpuUsage > 1)
}
}
]
}
Data filtering with regular expressions (as similar to setFilterRegularExpression) can be achieved through FunctionFilter (and sorting through the similar QML construct FunctionSorter) with the corresponding role name specified in the component to be used against.
SortFilterProxyModel {
id: sfpmProcessModel
model: processModel
sorters: [
RoleSorter {
roleName: "name"
column: 1
}
]
filters: [
FunctionFilter {
id: filter
component RoleData: QtObject {
property int pid
property string name
property string user
property string state
property int cpu
}
// JS regular expression comparision can be made as mentioned below
property var regExp: new RegExp(searchField.text, "i")
onRegExpChanged: invalidate()
function filter(data: RoleData) : bool {
if (searchField.text === "")
return true
switch (filterCb.currentIndex) {
case 0: return (data.pid == parseInt(searchField.text))
case 1: return regExp.test(data.name)
case 2: return regExp.test(data.user)
case 3: return regExp.test(data.state)
case 4: return (data.cpu >= parseInt(searchField.text))
default: true
}
}
}
]
}
The documentation to the SortFilterProxyModel contains detailed description about the corresponding filter and sorter properties and information related to it. The SortFilterProxyModel internally uses and adopts much of the same algorithms as QSortFilterProxyModel for data manipulation. The feature is in tech preview as of 6.10 and so please expect the change in APIs with the feedback.
Future scope
For future version, we are considering supporting nested filters and sorters.
The model attribute currently supports only the QAbstractItemModel. Still, the actual type of the model within SortFilterProxyModel had been chosen as QVariant, which, in the future, can be extended to support JavaScript arrays as well.
Also, defining the custom filters and sorters was not possible as of now, as their bases are internal, and they can be exposed in the future to accommodate this requirement.
Thanks for reading through this blog and your feedback on improvisation of this feature would really be helpful.
Blog Topics:
Comments
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.10 Now!
Download the latest release here: www.qt.io/download.
Qt 6.10 is now available, with new features and improvements for application developers and device creators.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.