Adding support for sorting and filtering on a list view will always be useful if the list view is much bigger and/or complex. I have created a simple demo QML based application which shows a basic list view with text item on which user can perform the filtering and sorting of items.

I have created CListModel class which is derived from QAbstractListModel which will hold the model data which is to be shown on the list view. I have also used a custom “NameRole” for the data.

Following is my CListModel class implementation.

#include <QAbstractListModel>

enum Roles {
 NameRole = Qt::UserRole + 1,
 };

//List Model
 class CListModel : public QAbstractListModel
 {
 public:
 CListModel();
 ~CListModel();

void addData(const QString &unit);

int rowCount(const QModelIndex & parent = QModelIndex()) const;

QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

protected:
 QHash<int, QByteArray> roleNames() const;

private:
 QStringList m_names;
 };

 

#include "listmodel.h"

CListModel::CListModel()
{

}

CListModel::~CListModel()
{

}

void CListModel::addData(const QString &unit)
{
 beginInsertRows(QModelIndex(), rowCount(), rowCount());
 m_names.append(unit);
 endInsertRows();
}

int CListModel::rowCount(const QModelIndex &parent) const
{
 Q_UNUSED(parent);
 return m_names.count();
}

QVariant CListModel::data(const QModelIndex &index, int role) const
{
 if (index.row() < 0 || index.row() >= m_names.count())
 return QVariant();

const QString &name = m_names[index.row()];
 if (role == NameRole)
 return name;
 return QVariant();
}

QHash<int, QByteArray> CListModel::roleNames() const
{
 QHash<int, QByteArray> roles;
 roles[NameRole] = "name";
 return roles;
}

 

Next we need a Filter model which will perform the sort and filter functionality on our custom list view. I have created FilterProxyModel class by deriving from QSortFilterProxyModel. And additionally I have added two methods for setting the filter string and sort criteria from the QML with macro Q_INVOKABLE.

Following is my FilterProxyModel class implementation.

class FilterProxyModel : public QSortFilterProxyModel
{
 Q_OBJECT
public:

FilterProxyModel(QObject* parent = 0);

~FilterProxyModel();

Q_INVOKABLE void setFilterString(QString string);

Q_INVOKABLE void setSortOrder(bool checked);
};

 

FilterProxyModel::FilterProxyModel(QObject *parent)
 : QSortFilterProxyModel(parent)
{
 setSortOrder(false);
}

FilterProxyModel::~FilterProxyModel()
{

}

void FilterProxyModel::setFilterString(QString string)
{
 this->setFilterCaseSensitivity(Qt::CaseInsensitive);
 this->setFilterFixedString(string);
}

void FilterProxyModel::setSortOrder(bool checked)
{
 if(checked)
 {
 this->sort(0, Qt::DescendingOrder);
 }
 else
 {
 this->sort(0, Qt::AscendingOrder);
 }
}

 

Below is my QML implementation.

import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
 id: appWindow
 visible: true
 width: 320
 height: 480
 color: "#6bdce4"
 property int margin: 12
 flags: Qt.FramelessWindowHint

ColumnLayout {
 id: mainLayout
 anchors.fill: parent
 anchors.margins: margin

Rectangle{
 color: "#6bdce4"
 Layout.fillWidth: true
 height: 40
 z: 2
 RowLayout {
 id: rowLayout
 anchors.fill: parent
 anchors.centerIn: parent
 TextField {
 placeholderText: "Type here.."
 Layout.fillWidth: true
 font.pointSize: 12
 style: TextFieldStyle {
 textColor: "black"
 background: Rectangle {
 radius: 5
 implicitWidth: 100
 implicitHeight: 30
 border.color: "#6bdce4"
 border.width: 1
 }
 }
 onTextChanged: {
 filterModel.setFilterString(text);
 }
 }
 CheckBox {
 text: "Descending"
 onCheckedChanged:{
 filterModel.setSortOrder(checked)
 }
 style: CheckBoxStyle {
 label: Text {
 color: "white"
 text: "Descending"
 font.pointSize: 12
 }
 indicator: Rectangle {
 implicitWidth: 20
 implicitHeight: 20
 radius: 3
 border.color: control.activeFocus ? "darkblue" : "gray"
 border.width: 1
 Rectangle {
 visible: control.checked
 color: "#555"
 border.color: "#333"
 radius: 1
 anchors.margins: 4
 anchors.fill: parent
 }
 }
 }
 }
 }
 }

ListView {
 id: view
 model: filterModel
 Layout.minimumHeight: 25
 Layout.fillHeight: true
 Layout.fillWidth: true
 cacheBuffer: 100
 spacing: 10

delegate: Rectangle{
 width: parent.width
 radius: 5
 anchors.horizontalCenter: parent.horizontalCenter
 height: 40
 color: Qt.lighter("#6bdce4", 0.8)
 Text {
 id: nameTxt
 text: name
 font.pointSize: 12
 color: "#FFFFFF"
 anchors.left: parent.left
 anchors.leftMargin: 20
 anchors.verticalCenter: parent.verticalCenter
 }
 }
 }
 }
}

 

Now first we need to create the instance of CListModel and populate the data which we want to show in the list. Then create an instance of filter model FilterProxyModel class and set the source as our actual model. Also set the role which we want to use for sorting and filtering. Now make the instance of FilterProxyModel available inside the QML file using method,

QQmlContext::setContextProperty("filterModel", &filterModel);

Below is my implementation of main.cpp file.

int main(int argc, char *argv[])
{
 QGuiApplication app(argc, argv);

 //Create and populate list model instance
 CListModel listModel;
 listModel.addData("Isaac Newton");
 listModel.addData("Alexander Graham Bell");
 listModel.addData("Leonhard Euler");
 listModel.addData("Nikola Tesla");
 listModel.addData("Charles-Augustin de Coulomb");
 listModel.addData("Andre-Marie Ampere");
 listModel.addData("Michael Faraday");
 listModel.addData("Blaise Pascal");
 listModel.addData("Anders Celsius");
 listModel.addData("James Watt");

 //Create filter model
 FilterProxyModel filterModel;
 filterModel.setSourceModel(&listModel);
 filterModel.setFilterRole(NameRole);
 filterModel.setSortRole(NameRole);

 QQmlApplicationEngine engine;
 QQmlContext* context = engine.rootContext();
 context->setContextProperty("filterModel", &filterModel);
 engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

 return app.exec();
}

Below are the screenshot from my demo application.

sortfilterdemo

Source code:

Git:/QMLSortFilterList

One thought on “QML List view Sort and Filter

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s