kossmoboleat
kossmoboleat

Reputation: 1951

QSortFilterProxyModel sort multiple columns

I am trying to implement a table that is sortable on more than one column. Qt's QSortFilterProxyModel only supports sorting on one column (at least in Qt 4.6.2).

I've found this solution by dimkanovikov on github, but it lacks dynamic updating on added rows. What I mean by this, is that the model is changed and the beginInsertRows(), beginRemoveRows(), their corresponding end..-methods and the dataChanged() signals are emitted. Ideally I would like to only these rows to be updated, but the model should at least react to such changes.

There's another FAQ item on Qt's site that sorts a QTableWidget, but it lacks dynamic updating, too.

I am new to Qt and I'd like to get some pointers on how I should go about this.

Upvotes: 2

Views: 10946

Answers (2)

kossmoboleat
kossmoboleat

Reputation: 1951

There's one slightly inelegant solution, that is always used to sort multiple columns.

You have to subclass QSortFilterProxyModel and reimplement bool lessThan(const QModelIndex &rLeft, const QModelIndex &rRight) const. Instead of only comparing between the two given indices, check all the columns:

int const left_row  = rLeft.row();
int const right_row = rRight.row();

int const num_columns = sourceModel()->columnCount();
for(int compared_column = rLeft.column(); compared_column<num_columns; ++compared_column) {
    QModelIndex const left_idx = sourceModel()->index(left_row, compared_column, QModelIndex());
    QModelIndex const right_idx = sourceModel()->index(right_row, compared_column, QModelIndex());

    QString const leftData = sourceModel()->data(left_idx).toString();
    QString const rightData = sourceModel()->data(right_idx).toString();

    int const compare = QString::localeAwareCompare(leftData, rightData);
    if(compare!=0) {
        return compare<0;
    }
}

return false;

Then you can call sort(0) on your QSortFilterProxyModel subclass and it will sort all the columns. Also don't forget to call setDynamicSortFilter(true) when you want the sorted rows to be dynamically resorted when the model data changes.

To support sorting on arbitrary columns in ascending or descending order, you would have to keep this info in a QList and compare accordingly when lessThan is called. In the list you would have the columns in order of their priority and do the comparisons in the same order. You should also sort the other "inactive" columns in some predefined order, otherwise they will not be sorted by default.

Upvotes: 8

romor
romor

Reputation: 1240

You can set the sorting role of the QSortFilterProxyModel to something different then the default Qt::DisplayRole withsetSortRole(Qt::UserRole). Then, in your model's data() method return a proper sort key if it gets called with the role Qt::UserRole, e.g. by concatenating the strings of the involved columns.

Upvotes: 9

Related Questions