Allows to apply filter and sorting settings to QML ListModel items. More...
Import Statement: | import Felgo 4.0 |
Since: | Felgo 2.18.1 |
SortFilterProxyModel is an implementation of QSortFilterProxyModel conveniently exposed for QML. You can use it to apply filter and sorting settings to your QML ListModel items.
The following relevant types are available:
Filter container accepting rows accepted by all its child filters |
|
Filter container accepting rows accepted by at least one of its child filters |
|
Filters row with a custom filtering |
|
Base type for the SortFilterProxyModel filters |
|
Filters rows based on their source index |
|
Filters rows between boundary values |
|
Filters rows matching a regular expression |
|
Base type for filters based on a source model role |
|
Filters rows matching exactly a value |
Abstract interface for types containing Filters |
Sorts row with a custom javascript expression |
|
Sorts rows based on if they match filters |
|
Sorts rows based on a locale aware comparison of a source model string role |
|
Sorts rows based on a source model role |
|
Base type for the SortFilterProxyModel sorters |
|
Sorts rows by comparing a source model string role with a localized collation algorithm |
Abstract interface for types containing Sorters |
A custom role computed from a javascript expression |
|
A role resolving to true for rows matching all its filters |
|
Role made from concatenating other roles |
|
Base type for the SortFilterProxyModel proxy roles |
|
A ProxyRole extracting data from a source role via a regular expression |
|
Base type for the SortFilterProxyModel proxy roles defining a single role |
|
A role using Filter to conditionnaly compute its data |
For detailed information on the SortFilterProxyModel, please see the project on GitHub.
The folowing example shows the configured entries of the ListModel in a ListPage, and allows to sort the list using the name
property:
import Felgo import QtQuick App { // data model ListModel { id: fruitModel ListElement { name: "Banana" cost: 1.95 } ListElement { name: "Apple" cost: 2.45 } ListElement { name: "Orange" cost: 3.25 } } // sorted model for list view SortFilterProxyModel { id: sortedFruitModel sourceModel: fruitModel // configure sorters sorters: [ LocaleAwareSorter { id: nameSorter roleName: "name" }] } // list page NavigationStack { ListPage { id: listPage title: "SortFilterProxyModel" model: sortedFruitModel delegate: SimpleRow { text: name detailText: "cost: "+cost style.showDisclosure: false } // add checkbox to activate sorter as list header listView.header: AppCheckBox { text: "Sort by name" checked: nameSorter.enabled updateChecked: false onClicked: nameSorter.enabled = !nameSorter.enabled anchors.horizontalCenter: parent.horizontalCenter height: dp(48) } } // ListPage } // NavigationStack } // App
The SortFilterProxyModel sorts the data whenever a sorter is enabled or disabled. In case you sequentially enable or disable multiple sorters within a single function or expression, each change requires an own sort operation.
In addition, the user interface can be shortly unresponsive while sorting is performed. To avoid such problems and move sorting into the background, enable the SortFilterProxyModel::delayed property:
import Felgo import QtQuick App { // data model ListModel { id: fruitModel ListElement { name: "Orange" cost: 3.25 } ListElement { name: "Banana" cost: 1.95 } ListElement { name: "Apple" cost: 3.75 } ListElement { name: "Banana" cost: 2.35 } ListElement { name: "Orange" cost: 1.25 } ListElement { name: "Apple" cost: 2.45 } } // sorted model for list view SortFilterProxyModel { id: sortedFruitModel // perform sort in the background, only sorts once when changing many sorters delayed: true sourceModel: fruitModel sorters: [ LocaleAwareSorter { id: nameSorter roleName: "name" }, LocaleAwareSorter { id: costSorter roleName: "cost" } ] } // list page NavigationStack { ListPage { id: listPage title: "SortFilterProxyModel" model: sortedFruitModel delegate: SimpleRow { text: name detailText: "cost: "+cost style.showDisclosure: false } // add checkbox to activate sorter as list header listView.header: AppCheckBox { text: "Sort by name and cost" checked: nameSorter.enabled updateChecked: false onClicked: { nameSorter.enabled = !nameSorter.enabled costSorter.enabled = nameSorter.enabled } height: dp(48) anchors.horizontalCenter: parent.horizontalCenter } } // ListPage } // NavigationStack } // App
Use the sortFinished() signal in case you want to run code after the sorting has completed.
This example loads JSON data from a REST API, wraps it in a QML ListModel and uses SortFilterProxyModel to apply filter and sorting settings:
import Felgo import QtQuick App { // full data model, will be filled with data loaded from REST API in loadTodos() ListModel { id: todoModel Component.onCompleted: loadTodos() // load data via http request function loadTodos() { HttpRequest.get("https://jsonplaceholder.typicode.com/todos") .then(function(res){ // map JSON to QML ListModel res.body.forEach(function(todo) { todoModel.append(todo) }) }) } } // filter settings are grouped in this item Item { id: filterSettings property bool sortByTitleActive: false property bool completedFilterActive: false property int userIdFilterValue: -1 } // filtered model for list view SortFilterProxyModel { id: filteredTodoModel sourceModel: todoModel // configure filters filters: [ ValueFilter { roleName: "completed" value: true enabled: filterSettings.completedFilterActive }, ValueFilter { roleName: "userId" value: filterSettings.userIdFilterValue enabled: filterSettings.userIdFilterValue > 0 }] // configure sorters sorters: [ LocaleAwareSorter { roleName: "title" enabled: filterSettings.sortByTitleActive }] } // list page NavigationStack { ListPage { id: listPage title: "SortFilterProxyModel" model: filteredTodoModel delegate: SimpleRow { text: title detailText: "user: "+userId+", completed: "+completed+", id: "+id style.showDisclosure: false } // add UI for filter options as list header listView.header: Column { x: spacing width: parent.width - 2 * spacing spacing: dp(5) // top spacer Item { width: parent.width; height: px(1) } // completed filter AppCheckBox { text: "Completed only" checked: filterSettings.completedFilterActive updateChecked: false onClicked: filterSettings.completedFilterActive = !filterSettings.completedFilterActive } // user id filter Row { spacing: parent.spacing AppText { text: "User ID" anchors.verticalCenter: parent.verticalCenter } AppTextField { id: userFilterText anchors.verticalCenter: parent.verticalCenter inputMethodHints: Qt.ImhFormattedNumbersOnly onAccepted: { if(text === "") filterSettings.userIdFilterValue = -1 else { userFilterText.text = parseInt(userFilterText.text) filterSettings.userIdFilterValue = userFilterText.text } listPage.forceActiveFocus() } } } // sort by title AppCheckBox { text: "Sort by title" checked: filterSettings.sortByTitleActive updateChecked: false onClicked: filterSettings.sortByTitleActive = !filterSettings.sortByTitleActive } // bottom spacer Item { width: parent.width; height: px(1) } } } // ListPage } // NavigationStack } // App
Use the SortFilterProxyModel::customSortOrder property to provide a list of desired positions for each entry.
import Felgo import QtQuick App { // data model ListModel { id: fruitModel ListElement { name: "Banana" cost: 1.95 } ListElement { name: "Apple" cost: 2.45 } ListElement { name: "Orange" cost: 3.25 } } // sorted model for list view SortFilterProxyModel { id: sortedFruitModel sourceModel: fruitModel customSortOrder: [1, 0, 2] // Apple, Banana, Orange } // list page NavigationStack { ListPage { id: listPage title: "SortFilterProxyModel" model: sortedFruitModel delegate: SimpleRow { text: name detailText: "cost: "+cost style.showDisclosure: false } // add checkbox to activate sorter as list header listView.header: AppButton { text: "Switch Position" onClicked: { var first = sortedFruitModel.customSortOrder[0] var second = sortedFruitModel.customSortOrder[1] sortedFruitModel.customSortOrder[0] = second sortedFruitModel.customSortOrder[1] = first } anchors.horizontalCenter: parent.horizontalCenter } } // ListPage } // NavigationStack } // App
The SortFilterProxyModel is also capable of acting as a proxy for a QML TableModel. To allow sorting data by role name and correctly access table columns, configure the columnRoleNames property.
The following example uses a TableModel and TableView together with SortFilterProxyModel:
import QtQuick import Felgo import Qt.labs.qmlmodels // for TableModel App { NavigationStack { AppPage { title: "Table Model Sorting" TableModel { id: myTableModel TableModelColumn { display: "checked" } TableModelColumn { display: "amount" } TableModelColumn { display: "fruitType" } TableModelColumn { display: "fruitName" } TableModelColumn { display: "fruitPrice" } // Each row is one type of fruit that can be ordered rows: [ { checked: true, amount: 4, fruitType: "Orange", fruitName: "Navel", fruitPrice: 2.50 }, { checked: false, amount: 1, fruitType: "Banana", fruitName: "Cavendish", fruitPrice: 3.50 }, { // Each property is one cell/column. checked: false, amount: 1, fruitType: "Apple", fruitName: "Granny Smith", fruitPrice: 1.50 } ] } SortFilterProxyModel { id: sortedModel sourceModel: myTableModel columnRoleNames: ["checked", "amount", "fruitType", "fruitName", "fruitPrice"] sorters: [ RoleSorter { id: priceSorter roleName: "fruitPrice" } ] } AppCheckBox { id: sortSetting text: "Sort by Price" anchors.horizontalCenter: parent.horizontalCenter checked: priceSorter.enabled updateChecked: false onClicked: priceSorter.enabled = !priceSorter.enabled y: dp(24) } TableView { anchors { top: sortSetting.bottom bottom: parent.bottom left: parent.left right: parent.right topMargin: dp(24) } columnSpacing: dp(12) rowSpacing: dp(12) model: sortedModel delegate: AppText { text: model.display padding: dp(6) } } } } }
Configures the role name for each column when using the SortFilterProxyModel with a QML TableModel. If set, the SortFilterProxyModel can retrieve data of each table cell with full support for role-based sorters and filters.
count : int |
The number of rows in the proxy model (not filtered out the source model)
This property allows to specify a list with custom ordering of items in the source model. Each entry in the list reflects target position of each item within the proxy model.
If a list of custom positions is specified, the proxy model ignores any sorter configuration.
See also sorters.
delayed : bool |
Delay the execution of filters, sorters and proxyRoles until the next event loop. This can be used as an optimization when multiple filters, sorters or proxyRoles are changed in a single event loop. They will be executed once in a single batch at the next event loop instead of being executed in multiple sequential batches.
By default, the SortFilterProxyModel is not delayed, unless the SFPM_DELAYED
environment variable is defined at compile time.
This property holds the list of filters for this proxy model. To be included in the model, a row of the source model has to be accepted by all the top level filters of this list.
See also Filter and FilterContainer.
This property holds the list of proxy roles for this proxy model. Each proxy role adds a new custom role to the model.
See also ProxyRole.
sortRoleName : string |
The role name of the source model's data used for the sorting.
See also QSortFilterProxyModel::sortRole and roleForName.
This property holds the list of sorters for this proxy model. The rows of the source model are sorted by the sorters of this list, in their order of insertion.
See also Sorter and SorterContainer.
sourceModel : QAbstractItemModel* |
The source model of this proxy model
filterFinished() |
This signal emits whenever the proxy model finishes filtering.
Note: When using delayed SortFilterProxyModel filtering, the filterFinished signal only fires once after all filters are applied. When not delayed, each filter change causes an own filterFinished signal.
Note: The corresponding handler is onFilterFinished
.
See also delayed.
sortFinished() |
This signal emits whenever the proxy model finishes sorting.
Note: The corresponding handler is onSortFinished
.
See also delayed.
Return the data for the given roleName of the item at row in the proxy model. This allows the role data to be read (not modified) from JavaScript. This equivalent to calling data(index(row, 0),
roleForName(roleName))
.
object get(int row) |
Return the item at row in the proxy model as a map of all its roles. This allows the item data to be read (not modified) from JavaScript.
Returns the row in the SortFilterProxyModel given the sourceRow from the source model. Returns -1 if there is no corresponding row.
QModelIndex mapFromSource(QModelIndex sourceIndex) |
Returns the model index in the SortFilterProxyModel given the sourceIndex from the source model.
Returns the source model row corresponding to the given proxyRow from the SortFilterProxyModel. Returns -1 if there is no corresponding row.
index mapToSource(index proxyIndex) |
Returns the source model index corresponding to the given proxyIndex from the SortFilterProxyModel.
Returns the role number for the given roleName. If no role is found for this roleName, -1
is returned.