Restore original order in QTableView / QSortFilterProxy

I have a QTableView with a QSortFilterProxyModel between the view and the model ( QStandardItemModel ). The problem is that when I call sort (), I cannot restore the original row order in the table. I tried to achieve this by changing the model proxy to QIdentityProxy on the fly, but to no avail, since the only change is that the lines are renumbered, but the order is sorted.

Is there any way to "cancel" the data? I think this code is not needed in this case, but will be sent if asked.

I am using Qt5 for Win x64

PS: the same problem was published here in 2009, but never received an answer.

+4
source share
5 answers

The bottom line is to manually sort between sorting by -1 column (recovery) and the normal column number and somehow intercept the connection between QHeaderView and QSortFilterProxyModel .

So, using some insight from @ vahancho's answer, I managed to sort as follows:

 class ProxyModel : public QSortFilterProxyModel { Q_OBJECT public: ProxyModel(QObject* parent = 0); signals: void askOrder(int column, Qt::SortOrder order); public slots: //! override of automatically called function void sort(int column, Qt::SortOrder order) { emit askOrder(column, order); } //! real sorting happens here void doSort(int column, Qt::SortOrder order) { QSortFilterProxyModel::sort(column, order); } }; 

and on the parent side I made the correct connection and checked:

 ResultsTable::ResultsTable(QWidget *parent) : QTableView(parent) { /*...*/ p_Header = new QHeaderView(this); p_Sort = new ProxyModel(this); connect(this, &ResultsTable::doSort, p_Sort, &ProxyModel::doSort); connect(p_Sort, &ProxyModel::askOrder, this, &ResultsTable::setSorting); /*...*/ setSortingEnabled(true); } void ResultsTable::setSorting(int column, Qt::SortOrder order) { if (p_Header->sortIndicatorOrder() == Qt::AscendingOrder && p_Header->isSortIndicatorShown() && m_PreviousSort == column) { p_Header->setSortIndicator(column, Qt::DescendingOrder); p_Header->setSortIndicatorShown(false); column = -1; } else { p_Header->setSortIndicatorShown(true); } m_PreviousSort = column; emit doSort(column, order); } 

That way, I can use the automatic sorting performed by QTableView when sortingEnabled is true . I tried to investigate what happens inside Qt when the table header is clicked to cause sorting, but it failed, so I stopped with this solution.

I'm still not sure if it is correct that the QTableView is responsible for setting the correct sort, and not the QHeaderView itself (since I thought this functionality should belong to the header).

+2
source

To restore the original unsorted state (verified)

  sortModel->setSortRole(Qt::InitialSortOrderRole); sortModel->invalidate(); 

QSortFilterProxyModel :: setSortRole (int role)

+3
source

As far as I understand, you need to return your sort to the default state? What if you override the QSortFilterProxyModel :: lessThan () function so that it returns the default value when you want to sort the reset, i.e.:

 return QSortFilterProxyModel::lessThan(left, right); 

and custom sort results when sorting is "on"? I think you will also need to reset your proxy model to its original state with QAbstractItemModel :: reset (). However, it will fill in all the model data, and you will lose information about the choice.

+2
source

I like to use the top left corner button to restore order (i.e. sort by the number of the line that this button is the title of). This works with standard classes in pyqt 5.9:

 def __init__(self): #... tb = self.tableView # has sorting enabled and SortIndicator shown proxy = QSortFilterProxyModel(self) proxy.setSourceModel(self.model) tb.setModel(proxy) btn = tb.findChild(QAbstractButton) if btn: btn.disconnect() btn.clicked.connect(self.disableSorting) tb.horizontalHeader().setSortIndicator(-1, 0) def disableSorting(self): self.tableView.model().sort(-1) self.tableView.horizontalHeader().setSortIndicator(-1, 0) 
0
source

This is what worked best for me:

 QSortFilterProxyModel *proxyModel = myTableView->model (); proxyModel->sort (-1); 

Note that this will not update the TableView header indicator, so before calling the above code, I also call:

 myTableView->horizontalHeader ()->setSortIndicator (0, Qt::DescendingOrder); 

I don't really like this, but I have not found a way to use TableView or HorizontalHeader to reset the QSortFilterProxyModel sort.

This is the full code:

 // Block QHeaderView signals so sorting doesn't happen twice myTableView->horizontalHeader ()->blockSignals (true); // Update the sort indicator to be the same as it was when the TableView was created myTableView->horizontalHeader ()->setSortIndicator (0, Qt::DescendingOrder); // Reset sorting QSortFilterProxyModel *proxyModel = myTableView->model (); proxyModel->sort (-1); // Unblock QHeaderView signals myTableView->horizontalHeader ()->blockSignals (false); 

NOTE. I block horizontal header signals temporarily to prevent QSortFilterProxyModel from sorting.

0
source

Source: https://habr.com/ru/post/1500733/


All Articles