2013-09-05 75 views
4

我有一個QTableViewQSortFilterProxyModel之間的視圖和模型(QStandardItemModel)。問題是當我調用sort()我無法恢復表中的行的原始順序。我試圖通過將模型代理更改爲QIdentityProxy來實現這一目標,但無濟於事,因爲唯一的變化是線條已重新編號,但順序保持排序。在QTableView/QSortFilterProxy中恢復原始訂單

有可能以某種方式「unsort」數據?我認爲,在這種情況下,代碼是不必要的,但如果被問到會發布。

我使用QT5在Win 64

P.S:同樣的問題被張貼here早在2009年,但從未有人接聽。

回答

2

重點是手動按列-1(恢復)和正常列號之間進行排序決定,並以某種方式攔截QHeaderViewQSortFilterProxyModel之間的通信。

因此,使用從@ vahancho的答案的一些見解,我已經成功地實現排序是這樣的:

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); 
    } 
}; 

,並在父母的身邊,我做出正確的連接和檢查:

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); 
} 

這我可以使用QTableView完成的自動分揀處理,當sortingEnabledtrue。我試圖研究當點擊表頭被誘導排序時發生的Qt內部事件,但失敗了,因此停止使用此解決方案。

我還不確定是否正確,QTableView負責設置正確的排序指示,而不是QHeaderView本身(因爲我認爲這個功能應該屬於標題)。

+0

這太棒了!它使每個標題像一個三態按鈕,並且視圖的默認狀態是未排序的。 – phyatt

2

我的理解是,你需要將你的排序返回到默認狀態?如果你重寫它,當你想重新排序返回默認值的方式QSortFilterProxyModel ::每種不超過()函數,即:

return QSortFilterProxyModel::lessThan(left, right); 

和排序「啓用」後,自定義排序結果?我認爲你還需要用QAbstractItemModel :: reset()重置你的代理模型到它的原始狀態。但是,它將重新填充整個模型數據,您將丟失選擇信息。

+0

你的理解是正確的。順便說一句,我現在對保持選擇不是很感興趣。我會馬上嘗試。 – sukhmel

+0

這個想法很好,但實現自定義lessThan只有在填充表格時纔有助於保持順序(比沒有更好)。分類完成後,根本沒有任何效果。 – sukhmel

+0

@idji在排序完成後是否嘗試重置模型?在重新設置模型之前,您需要在lessThan函數中禁用排序 - 這是我的想法。 – vahancho

0

我喜歡用左上角按鈕恢復順序(即,排序由行號到該按鈕是頭)。這適用於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

這是爲我工作最好的:

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

需要注意的是,這不會更新TableView中的頭指針,因此調用上面的代碼之前,我也美其名曰:

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

我真的不喜歡它,但我還沒有發現使用的TableView或Horizo​​ntalHeader重置QSortFilterProxyModel排序的方式。

這是全碼:

// 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); 

注:我阻斷水平頭信號暫時防止QSortFilterProxyModel排序從執行兩次。