#(48):QSortFilterProxyModel
從本章開始,我們將逐步了解有關自定義模型的相關內容。盡管前面我們曾經介紹過 Qt 提供的幾個內置模型:`QStringListModel`和`QFileSystemModel`,但對于千變萬化的需求而言,這些顯然是遠遠不夠的。于是,Qt 也允許我們對模型進行自定義。
在正式開始介紹自定義模形之前,我們先來了解一個新的類:`QSortFilterProxyModel`。之所以將這個類放在這里,是因為在一定程序上,我們可以使用`QSortFilterProxyModel`獲得一些可能必須自定義才能達到的效果。`QSortFilterProxyModel`并不能單獨使用。顧名思義,它是一個“代理”,其真正的數據需要另外的一個模型提供。它的作用是對數據進行排序和過濾。排序很好理解,而過濾,則是按照輸入的內容對數據及進行篩選,很像 Excel 里面的過濾器。不過 Qt 提供的過濾功能是基于正則表達式的,功能很強大。
下面我們根據代碼來了解下`QSortFilterProxyModel`的使用:
~~~
class SortView : public QWidget
{
Q_OBJECT
public:
SortView();
private:
QListView *view;
QStringListModel *model;
QSortFilterProxyModel *modelProxy;
QComboBox *syntaxBox;
private slots:
void filterChanged(const QString &text);
};
~~~
頭文件中,我們聲明了一個類`SortView`,繼承自`QWidget`。它有四個成員變量以及一個私有槽函數。
~~~
SortView::SortView()
{
model = new QStringListModel(QColor::colorNames(), this);
modelProxy = new QSortFilterProxyModel(this);
modelProxy->setSourceModel(model);
modelProxy->setFilterKeyColumn(0);
view = new QListView(this);
view->setModel(modelProxy);
QLineEdit *filterInput = new QLineEdit;
QLabel *filterLabel = new QLabel(tr("Filter"));
QHBoxLayout *filterLayout = new QHBoxLayout;
filterLayout->addWidget(filterLabel);
filterLayout->addWidget(filterInput);
syntaxBox = new QComboBox;
syntaxBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
syntaxBox->addItem(tr("Regular expression"), QRegExp::RegExp);
syntaxBox->addItem(tr("Wildcard"), QRegExp::Wildcard);
syntaxBox->addItem(tr("Fixed string"), QRegExp::FixedString);
QLabel *syntaxLabel = new QLabel(tr("Syntax"));
QHBoxLayout *syntaxLayout = new QHBoxLayout;
syntaxLayout->addWidget(syntaxLabel);
syntaxLayout->addWidget(syntaxBox);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(view);
layout->addLayout(filterLayout);
layout->addLayout(syntaxLayout);
connect(filterInput, SIGNAL(textChanged(QString)),
this, SLOT(filterChanged(QString)));
}
~~~
在構造函數中,我們首先創建一個`QStringListModel`對象,其內容是 Qt 預定義的所有顏色的名字(利用`QColor::colorNames()`獲取)。然后是`QSortFilterProxyModel`對象,我們將其原模型設置為剛剛創建的 model,也就是要為這個 model 進行代理;然后將`FilterKeyColumn`設置為 0,也就是僅僅對第一列進行過濾。我們使用一個`QStringListModel`包裝這個數據,這和前面的內容沒有什么區別。然后創建一個`QSortFilterProxyModel`對象,使用它的`setSourceModel()`函數將前面定義的`QStringListModel`傳進去,也就是我們需要對這個 model 進行代理。最后重要的一點是,`QListView`的數據源必須設置為`QSortFilterProxyModel`,而不是最開始的 model 對象。
作為過濾選項,syntaxBox 添加了三個數據項:
~~~
syntaxBox->addItem(tr("Regular expression"), QRegExp::RegExp);
syntaxBox->addItem(tr("Wildcard"), QRegExp::Wildcard);
syntaxBox->addItem(tr("Fixed string"), QRegExp::FixedString);
~~~
這正是正則表達式的幾種類型。正則表達式自己有一套相對通用的語法,但是對于不同的語言環境(例如 Java、C# 和 Python),其具體定義可能會略有差別。這里我們使用的是 Qt 自己的正則表達式處理工具(C++ 本身并沒有解析正則表達式的機制,雖然 boost 提供了一套)。第一個`QregExp::RegExp`提供了最一般的正則表達式語法,但這個語法不支持貪婪限定符。這也是 Qt 默認的規則;如果需要使用貪婪限定符,需要使用`QRegExp::RegExp2`。盡管在 Qt4 的文檔中聲明,`QRegExp::RegExp2`將會作為 Qt5 的默認規則,但其實并不是這樣。第二個我們提供的是 Unix shell 常見的一種規則,使用通配符處理。第三個即固定表達式,也就是說基本上不使用正則表達式。
接下來我們看看 filterChanged() 函數的實現:
~~~
void SortView::filterChanged(const QString &text)
{
QRegExp::PatternSyntax syntax = QRegExp::PatternSyntax(
syntaxBox->itemData(syntaxBox->currentIndex()).toInt());
QRegExp regExp(text, Qt::CaseInsensitive, syntax);
modelProxy->setFilterRegExp(regExp);
}
~~~
在這段代碼中,首先使用`QComboBox`的選擇值創建一個`QRegExp::PatternSyntax`對象;然后利用這個語法規則構造一個正則表達式,注意我們在`QLineEdit`里面輸入的內容是通過參數傳遞進來的,然后設置數據模型代理的過濾表達式。下面可以運行一下看看結果:
[](http://files.devbean.net/images/2013/04/proxymodel-demo.png)
上圖中,我們輸入的是 gr[ae]y 作為正則表達式。這是說,我們希望獲取這樣一個顏色的名字:它的名字中有這樣的四個字母,第一個字母是 g,第二個字母是 r,第三個字母要么是 a,要么是 e,第四個字母是 y。如果找到符合條件的名字,就要把它過濾出來,顯示到列表中,不符合條件的全部不顯示。我們的程序正是這樣的結果。如果你對這個正則表達式不熟悉,請自行查閱有關正則表達式的內容。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)