QT:QSortFilterProxyModel代理實現排序、過濾

在之前60.QT-QabstractTableModel模型、重寫sort方法排序章節中,學習瞭如何用model,本章再來學習QSortFilterProxyModel代理

1. QsortFilterProxyModel介紹

QsortFilterProxyModel類用來爲model和view之間提供強大的排序和過濾支持。將模型排序或者過濾後在視圖上顯示,並且無需對模型中的數據進行任何轉換,也無需對模型在中數據進行修改。

比如: 對某列篩選帶有”xxx”的關鍵字出來.並支持多則表達式

使用代理的項視圖模型代碼如下:

QTreeView *treeView = new QTreeView;  
MyItemModel *sourceModel = new MyItemModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel); //將model放入代理中 
treeView->setModel(proxyModel); //在視圖中安裝代理

2.QSortFilterProxyModel自定義排序

自定義排序需要子類化QsortFilterProxyModel,然後重寫lessThan().

注意 : 如果重寫了lessThan(),那麼就不會再調用model的sort方法了.

lessThan()使用示例:

bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
    //通過當前視圖中的index位置獲取model中實際的數據
    QVariant leftData = sourceModel()->data(source_left);
    QVariant rightData = sourceModel()->data(source_right);
    switch ( source_left.column() )
    {
        case 0 :     //序號,需要判斷數字
        case 3 :     //信號ID,需要判斷數字
            return leftData.toInt() < rightData.toInt();
            break;
        default :    //其它,只判斷字符串
            return leftData.toString() < rightData.toString();
            break;
    }
 
    return true;     
 
}

除了排序外,QSortFilterProxyModel還可以用來隱藏與某個過濾器不匹配的項。使用QRegExp對象指定篩選器,並將篩選器應用於給定列的每個項的filterRole() (默認情況下爲Qt::DisplayRole)。QRegExp對象可用於匹配正則表達式、通配符模式或固定字符串。

3.過濾方法1-使用setFilterKeyColumn()過濾列

首先需要通過void QsortFilterProxyModel::setFilterRegExp(const QRegExp &regExp)來設置FilterProxyModel的過濾器.

然後通過QsortFilterProxyModel::setFilterKeyColumn(int)來過濾某一列.

如果要更改大小寫匹配,可以通過QsortFilterProxyModel::sortCaseSensitivity()來設置.

示例代碼如下所示:

QTableView *view = new QTableView;   
MyItemModel *sourceModel = new MyItemModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel); //將model放入代理中   
view->setModel(proxyModel);             //在視圖中安裝代理

QRegExp regExp("^(-?\\d+)(\\.\\d+)?$", Qt::CaseSensitive, QRegExp::RegExp);
//通過^(-?\d+)(\.\d+)?$來匹配整數
proxyModel->setFilterRegExp(regExp);   //安裝過濾器

proxyModel->setFilterKeyColumn(0);    
proxyModel->setFilterKeyColumn(2);    //將第一列和第三列同時是整數的數據顯示出來.

每當過濾格式改變,則setFilterRegExp()重新更新過濾器即可.

弊端:

  • 但是這樣只能"與方式"顯示model,要第一列和第三列公共是整數的才能顯示出來,不能實現"或方式"顯示.

所以,如果要使用聯合多列過濾,建議使用過濾方法2來實現.

4.過濾方法2-重寫filterAcceptsRow成員函數

以實現"只要第一列有整數或者第三列有整數的都顯示出來"爲例,首先需要子類化QsortFilterProxyModel類,然後重寫filterAcceptsRow()或者filterAcceptsColumn()函數.

由於我們篩選第一列和第三列,列號是明確的,而行號是未知的, 所以我們只重寫filterAcceptsRow()函數.

示例代碼如下所示:

bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
    //獲取model中實際的數據
    QString dataColumn1 =  sourceModel()->index(source_row, 0, source_parent).data(Qt::DisplayRole).toString();
    QString dataColumn3 =  sourceModel()->index(source_row, 2, source_parent).data(Qt::DisplayRole).toString();
    if(dataColumn1.contains(this->filterRegExp()))     
    {
        return true;
    }
    else if(dataColumn3.contains(this->filterRegExp())) 
    {
        return true;
    }
    return false;        
 
}

然後創建SortFilterProxyModel類時,只需要安裝過濾器即可:

SortFilterProxyModel *proxyModel = new SortFilterProxyModel();
proxyModel->setSourceModel(sourceModel);            //將model放入代理中   
treeView->setModel(proxyModel);                     //在視圖中安裝代理
proxyModel->setFilterRegExp("^(-?\\d+)(\\.\\d+)?$"); //安裝過濾器

每當過濾格式改變,則setFilterRegExp()重新更新過濾器即可.

注意事項:

  • 如果過濾方式改變了,比如從過濾第1列變成了過濾第2列,需要調用invalidateFilter()函數,使之前的過濾失效,激活當前過濾.

5.代碼示例

model採用上章代碼的CustomModel爲例.支持篩選多列、篩選模式支持:或方式、與方式、

界面實現如下所示:

sortfilterproxymodel.h:

#ifndef SORTFILTERPROXYMODEL_H
#define SORTFILTERPROXYMODEL_H

#include <QObject>
#include <QSortFilterProxyModel>
#include <QList>

class SortFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT

    virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
    virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
    bool m_isOr;
    QList<int> m_selectdList;

public:
    explicit SortFilterProxyModel(QSortFilterProxyModel *parent = nullptr);

    void ChangeFilterMode(bool isOr);        
    void ChangeFilterColumn( QList<int> selectdList);         

signals:

};

#endif // SORTFILTERPROXYMODEL_H

sortfilterproxymodel.cpp:

#include "sortfilterproxymodel.h"
#include <QDebug>
SortFilterProxyModel::SortFilterProxyModel(QSortFilterProxyModel *parent)
    : QSortFilterProxyModel(parent)
{

}


void SortFilterProxyModel::ChangeFilterMode(bool isOr)    
{
    m_isOr = isOr;
    invalidateFilter();
}
void SortFilterProxyModel::ChangeFilterColumn( QList<int> selectdList)     
{
    m_selectdList = selectdList;
    invalidateFilter();
}


bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{

    if(m_selectdList.isEmpty())
        return true;

    foreach(int column, m_selectdList) {

         QString data =  sourceModel()->index(source_row, column, source_parent).data(Qt::DisplayRole).toString();

         bool mathd = this->filterRegularExpression().match(data).hasMatch();


         if(m_isOr && mathd) {    
           return true;
         } else if(!m_isOr && !mathd) {     
             return false;
         }

    }

    if(m_isOr)          
        return false;
    else
        return true;
}

bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
    //通過當前視圖中的index位置獲取model中實際的數據
    QVariant leftData = sourceModel()->data(source_left);
    QVariant rightData = sourceModel()->data(source_right);

    switch ( source_left.column() )
    {
        case 0 :  
        case 3 :   
            return leftData.toInt() < rightData.toInt();
            break;
        default :    
            return leftData.toString() < rightData.toString();
            break;
    }


    return true;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章