2012-06-05 25 views
2

Я пытаюсь реализовать таблицу, сортируемую в нескольких столбцах. QS QSortFilterProxyModel поддерживает только сортировку по одному столбцу (по крайней мере, в Qt 4.6.2).QSortFilterProxyModel сортировать несколько столбцов

Я нашел this solution от dimkanovikov на github, но ему не хватает динамического обновления на добавленные строки. Я имею в виду, что модель изменена, и beginInsertRows(), beginRemoveRows(), их соответствующие end ..- методы и сигналы dataChanged() испускаются. В идеале я хотел бы обновлять только эти строки, но модель должна хотя бы реагировать на такие изменения.

На сайте Qt есть другой раздел вопросов, который сортирует QTableWidget, но ему также не хватает динамического обновления.

Я новичок в Qt, и я хотел бы получить несколько указателей на то, как я должен это делать.

+1

В качестве примечания: если вы сортируете столбец B, а затем столбец A, все строки с тем же значением в A должны быть отсортированы по B. Такой тип позволяет провести обратную сортировку, т.е. если вы хотите сортировать для A, тогда B, то C, вы должны фактически сортировать таблицу с помощью C, затем B, затем A –

+0

. Обратное сортирование может работать быстрее, чем решение, с которым я пошел, но тогда вам придется переопределить '' void QAbstractItemModel :: sort (int column , Qt :: SortOrder order = Qt :: AscendingOrder) и, вероятно, сложнее реализовать то, что я сделал. – kossmoboleat

+0

То, что я описал, не требует дополнительной реализации, это поведение по умолчанию Qt. Это просто, если вы нажмете столбец B, тогда столбец A в стандартном QTableView (разрешенная сортировка включена для этих столбцов), и есть строки, которые имеют то же значение A, но разные значения B, эти значения B также будут отсортированы. Ваше собственное решение, вероятно, будет лучше для вашего дела, хотя –

ответ

5

Существует одно слегка неэлегантное решение, которое всегда используется для сортировки нескольких столбцов.

У вас должен быть подкласс QSortFilterProxyModel и reimplement bool lessThan(const QModelIndex &rLeft, const QModelIndex &rRight) const. Вместо того, чтобы только сравнение между двумя заданными индексами, проверьте все столбцы:

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; 

Тогда вы можете вызвать sort(0) на вашем QSortFilterProxyModel подкласса, и он будет сортировать все столбцы. Также не забудьте позвонить setDynamicSortFilter(true), если вы хотите, чтобы отсортированные строки были динамически использованы при изменении данных модели.

Чтобы поддерживать сортировку по произвольным столбцам в порядке возрастания или убывания, вам необходимо сохранить эту информацию в QList и соответственно сравнить их при вызове lessThan. В списке вы должны иметь столбцы в порядке их приоритета и выполнять сравнения в том же порядке. Вы также должны сортировать другие «неактивные» столбцы в некотором предопределенном порядке, иначе они не будут сортироваться по умолчанию.

+2

+1 для setDynamicSortFilter – qwerty9967

+0

Этот метод можно даже безопасно применять к 'QTableWidget'. Вам просто нужно подклассифицировать 'QTableWidgetItem' и переопределить метод' __lt__' – swdev

+0

Обратите внимание, что приведенная выше реализация игнорирует sortRole. Хорошая реализация будет использовать набор sortRole для прокси-модели для запроса данных для сравнения. Также обратите внимание, что преобразование в строки может быть не лучшим способом сравнения значений.Если столбец содержит даты или цифры, сравнение на основе строк приведет к неестественным порядкам сортировки. –

7

Вы можете установить сортировочную роль QSortFilterProxyModel на что-то другое, чем по умолчанию Qt::DisplayRole с setSortRole(Qt::UserRole). Затем в методе data() вашей модели верните правильный ключ сортировки, если он вызван с ролью Qt::UserRole, например. путем объединения строк соответствующих столбцов.

+0

Интересно! Это тоже сработает. – kossmoboleat