Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

SortFilterProxyModel

Allows to apply filter and sorting settings to QML ListModel items. More...

Import Statement: import Felgo 4.0
Since: Felgo 2.18.1

Properties

Signals

Methods

Detailed Description

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:

Types

Filter

AllOf

Filter container accepting rows accepted by all its child filters

AnyOf

Filter container accepting rows accepted by at least one of its child filters

ExpressionFilter

Filters row with a custom filtering

Filter

Base type for the SortFilterProxyModel filters

IndexFilter

Filters rows based on their source index

RangeFilter

Filters rows between boundary values

RegExpFilter

Filters rows matching a regular expression

RoleFilter

Base type for filters based on a source model role

ValueFilter

Filters rows matching exactly a value

FilterContainer

Abstract interface for types containing Filters

Sorter

ExpressionSorter

Sorts row with a custom javascript expression

FilterSorter

Sorts rows based on if they match filters

LocaleAwareSorter

Sorts rows based on a locale aware comparison of a source model string role

RoleSorter

Sorts rows based on a source model role

Sorter

Base type for the SortFilterProxyModel sorters

StringSorter

Sorts rows by comparing a source model string role with a localized collation algorithm

SorterContainer

Abstract interface for types containing Sorters

ProxyRole

ExpressionRole

A custom role computed from a javascript expression

FilterRole

A role resolving to true for rows matching all its filters

JoinRole

Role made from concatenating other roles

ProxyRole

Base type for the SortFilterProxyModel proxy roles

RegExpRole

A ProxyRole extracting data from a source role via a regular expression

SingleRole

Base type for the SortFilterProxyModel proxy roles defining a single role

SwitchRole

A role using Filter to conditionnaly compute its data

For detailed information on the SortFilterProxyModel, please see the project on GitHub.

Example Usage

Simple Example

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

Optimize Performance by Sorting in the Background

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.

Advanced Example

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

Sorting the Model in a Custom Order

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

Sorting Example with TableModel and TableView

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)
         }
       }
     }
   }
 }

Property Documentation

columnRoleNames : list<string>

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)


customSortOrder : list<int>

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.


filters : list<Filter>

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.


proxyRoles : list<ProxyRole>

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.


sorters : list<Sorter>

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


Signal Documentation

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.


Method Documentation

variant get(int row, string roleName)

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.


int mapFromSource(int sourceRow)

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.


int mapToSource(int proxyRow)

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.


int roleForName(string roleName)

Returns the role number for the given roleName. If no role is found for this roleName, -1 is returned.


Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded