mrg95
mrg95

Reputation: 2418

QSortFilterProxyModel sort based on two sort roles?

In my project, I have a model displayed in a treeview. I used QSortFilterProxyModel to sort the model based on an ID set in Qt::UserRole+1. This divides my list by "type" (as you can tell by the icons used):

enter image description here

However I also want each "type" to be sorted alphabetically. I initially tried to sort things alphabetically FIRST and THEN sort it by type to see if it would rearrange things to work properly, but it stays the same. Is there any way to tell my program to sort with two sort roles AND determine which one "goes first?"

proxy->setSortRole(Qt::DisplayRole);
proxy->setSortRole(Qt::UserRole+1);

Upvotes: 4

Views: 6755

Answers (3)

mrg95
mrg95

Reputation: 2418

All I needed to do was create a proxy model of another proxy model. The first proxy ordered things alphabetically, the second proxy ordered the first proxy by UserRole+1.

QSortFilterProxyModel* proxy = new QSortFilterProxyModel(ui->treeNBT);
proxy->setSourceModel(model);
proxy->setDynamicSortFilter(false);
proxy->sort(0, Qt::AscendingOrder);
proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
proxy->setSortRole(Qt::DisplayRole);
QSortFilterProxyModel* proxy2 = new QSortFilterProxyModel(ui->treeNBT);
proxy2->setSourceModel(proxy);
proxy2->setDynamicSortFilter(false);
proxy2->sort(0, Qt::AscendingOrder);
proxy2->setSortRole(Qt::UserRole+1);
ui->treeNBT->setModel(proxy2);

Much simpler than writing custom sort logic in a reimplemented class. There is no noticeable performance hit, so this is what I'm using.

Edit: Changed my answer... looking back at my old questions, and this isn't the best way to go about this. Reimplementing the class was the better (and obvious) way. oops.

Upvotes: 6

krojew
krojew

Reputation: 1336

You need to subclass the proxy and implement your own lessThan().

The QSortFilterProxyModel uses a virtual lessThan method to determine the ordering between model indexes. Only the default implementation of lessThan respects the role set by setSortRole. You can override it to provide custom sorting behavior, in which case setSortRole is obsolete.

The official documentation has a section on custom sorting along with a code sample: http://doc.qt.io/qt-5/qsortfilterproxymodel.html#details

Upvotes: 1

László Papp
László Papp

Reputation: 53173

Since my duplicate urls were nuked, here goes the working example right from the official example after some minor adjustment:

class MySortFilterProxyModel Q_DECL_FINAL : public QSortFilterProxyModel
{
    Q_OBJECT

public:
    MySortFilterProxyModel(QObject *parent)
        : QSortFilterProxyModel(parent)
    {
    }

protected:
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE
    {
        QVariant leftData = sourceModel()->data(left);
        QVariant rightData = sourceModel()->data(right);
        // Do custom logic in here, e.g.:
        return QString::localeAwareCompare(leftData.toString(), rightData.toString()) < 0;
    }
};

Then, this custom class would be used normally in place of the original as a drop-in replacement. That is it!

Upvotes: 1

Related Questions