Reputation: 1492
I have a QTableView
with QSortFilterProxyModel
between the view and the model (QStandardItemModel
). The problem is when I call sort() I'm unable to restore original order of lines in a table. I was trying to acheve that by changing model proxy to QIdentityProxy
on-the-fly but to no avail, as the only change is that lines are renumbered but order is kept sorted.
Is it possible to somehow "unsort" data? I think, that code is unnecessary in this case, but will post if asked.
I'm using Qt5 on Win x64
P.S.: The same problem was posted here back in 2009 but never was answered.
Upvotes: 6
Views: 7307
Reputation: 66
one interesting fact:
if you have your source model being sorted by more than one criteria for example QSqlQuerModel *source_model where the query contians "ORDER BY familyName, Name" than setting sort(-1) will not be enough
you will have to disable sortingEnabled property of the QTableView that is using this model to revert to sorting by 2 criterias
Upvotes: 1
Reputation: 574
From the docs:
QSortFilterProxyModel can be sorted by column -1, in which case it returns to the sort order of the underlying source model.
So, as @eTHP says, sort(-1)
does the trick!
Upvotes: 0
Reputation: 81
This is what worked best for me:
QSortFilterProxyModel *proxyModel = myTableView->model ();
proxyModel->sort (-1);
Note that, this won't update the header indicator of a TableView, so before calling the code above, I'm also calling:
myTableView->horizontalHeader ()->setSortIndicator (0, Qt::DescendingOrder);
I don't really like it, but I haven't found a way of using the TableView or HorizontalHeader to reset the QSortFilterProxyModel sorting.
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'm blocking the horizontal header signals temporarily to prevent QSortFilterProxyModel sort from executing twice.
Upvotes: 2
Reputation: 4219
I like to use top-left corner button to restore order (that is, sort by row number to which that button is the header). 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)
Upvotes: 2
Reputation: 1667
To restore initial unsorted state ( tested )
sortModel->setSortRole(Qt::InitialSortOrderRole);
sortModel->invalidate();
QSortFilterProxyModel::setSortRole(int role)
Upvotes: 5
Reputation: 1492
The point is to sort manually deciding between sort by column -1 (restore) and normal column number, and intercept communication between QHeaderView
and QSortFilterProxyModel
somehow.
So, using some insight from @vahancho's answer, I've managed to implement sorting like this:
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 parent's side I made proper connection and checks:
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);
}
this way I can use automatic sorting treating done by QTableView
when sortingEnabled
is true
. I've tried to research what happens inside of Qt when table header is clicked to induce sorting, but failed, so stopped with this solution.
I'm still unsure if it's right that this way QTableView
is responsible for setting correct sort indication, and not QHeaderView
itself (as I thought this functionality should to belong to the header).
Upvotes: 4
Reputation: 21258
My understanding is that you need to return your sorting to its default state? What if you override the QSortFilterProxyModel::lessThan() function in the way that it returns the default value when you want to reset sorting, i.e.:
return QSortFilterProxyModel::lessThan(left, right);
,and custom sorting results when sorting "enabled"? I think you will also need to reset your proxy model to its original state with QAbstractItemModel::reset(). However, it will repopulate the whole model data and you will lost selection information.
Upvotes: 2