How to sort in TableView like QTableView?
-
i select a row like this
it will display after sort like this
how to let table view select the same data after a sort?
mymodel
//Header #ifndef TABLEVIEWMODEL_H #define TABLEVIEWMODEL_H #include <QAbstractTableModel> struct TableViewItem { int iNumber; QString strName; }; class TableViewModel : public QAbstractTableModel { Q_OBJECT Q_PROPERTY(QString sortRole READ sortRole WRITE setSortRole) public: enum {Role_Number = Qt::UserRole + 1, Role_Name}; TableViewModel(QObject *parent); virtual ~TableViewModel() override; // QAbstractItemModel interface public: int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QString sortRole() const; void setSortRole(QString sortRole); // QAbstractItemModel interface public: QHash<int, QByteArray> roleNames() const override; protected: int sortKey(const QString &name) const; protected: QVector<TableViewItem> mData; QString mSortRole; }; #endif // TABLEVIEWMODEL_H //CPP #include "tableviewmodel.h" #include <algorithm> #include <QDebug> #include <QMap> TableViewModel::TableViewModel(QObject *parent) : QAbstractTableModel(parent) { mData.push_back({1, "Candy"}); mData.push_back({2, "John"}); } TableViewModel::~TableViewModel() { } int TableViewModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return mData.size(); } int TableViewModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 2; } QVariant TableViewModel::data(const QModelIndex &index, int role) const { if(!hasIndex(index.row(), index.column())) return QVariant(); switch (role) { case Role_Number: return mData[index.row()].iNumber; case Role_Name: return mData[index.row()].strName; } return QVariant(); } QHash<int, QByteArray> TableViewModel::roleNames() const { QHash<int, QByteArray> roleName; roleName[Role_Number] = "number"; roleName[Role_Name] = "name"; return roleName; } QString TableViewModel::sortRole() const { return mSortRole; } void TableViewModel::setSortRole(QString sortRole) { mSortRole = sortRole; QVector<QPair<TableViewItem,int>> sortable; for (int row = 0; row < rowCount(QModelIndex()); ++row) { sortable.append({mData[row], row}); } beginResetModel(); int role = sortKey(mSortRole); switch (role) { case Role_Name: { std::stable_sort(mData.begin(), mData.end(), [](const TableViewItem &rhs, const TableViewItem &lhs){ return lhs.strName < rhs.strName; }); } break; case Role_Number: { std::stable_sort(mData.begin(), mData.end(), [](const TableViewItem rhs, const TableViewItem& lhs){ return lhs.iNumber < rhs.iNumber; }); } break; } endResetModel(); } int TableViewModel::sortKey(const QString &name) const { auto roleName = roleNames(); for(auto it = roleName.begin(); it != roleName.end(); ++it) { if(it.value() == name) return it.key(); } return -1; } //QML import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 as Ctrl14 import QtQuick.Controls 2.4 import QtQuick.Controls.Styles 1.4 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Ctrl14.TableView { x: 34 y: 64 width: 349 height: 343 id: tableView sortIndicatorVisible: true objectName: "tableView" selectionMode: Ctrl14.SelectionMode.ExtendedSelection Ctrl14.TableViewColumn { role: "number" title: "No." } Ctrl14.TableViewColumn { role: "name" title: "Name" } onSortIndicatorColumnChanged: { model.sortRole = tableView.getColumn(tableView.sortIndicatorColumn).role } } Button { id: button x: 397 y: 378 width: 74 height: 29 text: qsTr("Button") } }
-
Hi,
What version of Qt ?
On what OS ?
What type of model ?
How do you implement the sorting ? -
What happens if rather than the begin/endResetModel, you just call dataChanged ?
-
I think, I don't need to call dataChanged
?
My advice would be: if @SGaist suggests you try something you heed it!
When you call
beginResetModel
Qt throws away all existing information about the model, including which row was selected. The view presumably then just remembers row #2 was selected and reselects that.If instead you call
dataChanged
on each index it may remember which row in the model was selected and re-select the model row, not the view row number.Otherwise, if that does not work or you wish to stick
beginResetModel
, before you sort you should store which row is selected by its content. That is usually the primary key, which looks like it might be youriNumber
? Then after the sort you go find that row again by its content and reselect that. Any problem with that? -
and store selected and reselect is a good idea, but when I select large of data, it will be very slow,
Sorry, I don't understand? All you are supposed to store is the key of whichever row was previously selected, and then you re-find that in the new data order and select that item. What would be "slow"?
-
@JohnDaYe
Yes, but why in the world would you want to select a row 10,000 times, or reselect a given row 10,000 times?I just don't get what you don't get?
- Store the primary key of the currently selected row somewhere.
- Call
beginResetModel
, do the sort,endResetModel
. - Look through the rows in the newly-ordered model to find what the index is now of the row whose primary key you saved away. (Depending on what it's sorted by, this may be optimizable, or not.)
- Call
tableview.selection.select(index)
.
I haven't called
select()
10,000 times, have I? I'm just selecting one row at the end.