13.6.2 QSortFilterProxyModel的应用(1)
前一节介绍了如何直接派生QAbstractProxyModel的子类,以将源模型中的数据集映射为另外一个虚拟的数据集。这种方法虽然足够灵活,但是需要程序员实现两个数据集索引的映射,并且需要重载多个接口函数。如果这种映射只是对源模型中的数据项进行过滤以及排序,我们可以使用Qt提供的代理模型QSortFilterProxyModel。
该类采用了与前一节类似的思路,实现代理模型与源模型索引之间的映射,重载多个接口函数以使其他视图对象能够访问代理模型中的虚拟数据集。在实现索引之间的映射时,该类考虑了过滤与排序两种操作。关于过滤操作,该类的成员函数setFilterRegExp()设置一个过滤条件,成员函数setFilterKeyColumn()将这个过滤条件施加到源模型的某一列,使得只有部分行的源数据项被映射到代理模型,其他行的数据项被过滤出局。关于排序操作,该类实现了抽象基类QAbstractItemModel定义的接口函数sort(),也即
- void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
在这个函数中,该类构建源数据项索引与虚拟数据项索引之间的映射关系,以使得映射后的数据项按照第column列排为升序或者降序(由参数order指定)。
使用QSortFilterProxyModel时,程序员需要调用与过滤相关的成员函数,设置过滤条件。但是,程序员并不需要直接调用与排序相关的成员函数,因为视图对象知道所有模型都提供上述接口函数sort(),因而当用户单击视图某列标头要求排序时,视图对象会自动调用QSortFilterProxyModel的sort()函数。
还有另外一种方法对源模型中的数据项进行排序:令源模型自己实现这个sort()函数,然后令一个视图对象直接显示这个源模型。当用户需要排序时,视图对象会直接调用源模型的sort()函数对数据项进行排序。然而,这种方法会更改源数据项的物理存放位置,不像代理模型的sort()函数那样,只是对虚拟数据项进行排序。
下面我们将使用Qt提供的一个例子来演示QSortFilterProxyModel的作用。该例子能够对一组电子邮件的摘要信息进行过滤、排序。这个例子的输出如图13 23所示。每条电子邮件的摘要信息包括邮件主题(subject)、发送者(sender)以及发送时间(date)。这些数据项组成源模型的数据集,被显示在窗口上方。窗口中间部分显示代理模型中的数据项,用户单击某列的标头,视图将依据该列中的数据,将代理模型中的各行数据排为升序或者降序。连续地单击将在升序和降序之间切换。用户可以使用三种格式输入过滤条件:正则表达式、通配符或者固定的字符串,其中正则表达式的表达能力最强,本节仅讲述这种格式。关于正则表达式,读者可参考文献[25]及[26]。界面下方和过滤相关,用户在第一行输入过滤条件,在第二行选择过滤条件的格式,在第三行选择这个过滤条件施加于哪列。图中用户的选择表示:对"Sender"列施加一个正则表达式"Andy|Grace",表示只要源模型某行的"Sender"列出现字符串"Andy"或者"Grace",该行就会被代理模型接收。
|
| (点击查看大图)图13 23 类QSortFilterProxyModel的应用 |
本例中的主要类如图13 24所示。该例的主函数main()创建一个QStandardItemModel对象,作为QSortFilterProxyModel的源模型。QWidget的子类Window是应用程序的主界面,其构造函数创建一个QSortFilterProxyModel对象、两个QTreeView视图对象,其中一个视图对象被用来显示QSortFilterProxyModel中的虚拟数据项,另外一个被用来显示源模型中的数据项。
|
| 图13 24 例子basicSortFilterModel的类图 |
创建源模型的函数如代码段13 25所示,主要是创建一个QStandardItemModel对象,并向其中添加若干行数据。行①调用的函数insertRow()具有原型:
- bool QStandardItemModel::insertRow ( int row,
- const QModelIndex & parent = QModelIndex() )
表示在parent所指的父节点的第row行子节点之前插入一个新行。由于本例的源模型是一个简单的表格,所有数据项的父节点都是这个不可见根,因而行①第二个实参取默认值QModelIndex(),也即无效索引,表示在不可见根的第row行之前插入一个新行。类似地,行②调用的index()函数本来具有三个参数,但是第三个参数取默认值QModelIndex(),表示返回不可见根下某个数据项的索引。
代码段13 25,创建源模型,取自z:\examples\mvc\basicsortfiltermodel\main.cpp
- void addMail(QAbstractItemModel *model, const QString &subject,
- const QString &sender, const QDateTime &date)
- {
- model->insertRow(0); ①
- model->setData(model->index(0, 0), subject); ②
- model->setData(model->index(0, 1), sender);
- model->setData(model->index(0, 2), date);
- }
- QAbstractItemModel *createMailModel(QObject *parent)
- {
- QStandardItemModel *model = new QStandardItemModel(0, 3, parent);
- model->setHeaderData(0, Qt::Horizontal, QObject::tr("Subject"));
- model->setHeaderData(1, Qt::Horizontal, QObject::tr("Sender"));
- model->setHeaderData(2, Qt::Horizontal, QObject::tr("Date"));
- addMail(model, "Happy New Year!", "Grace K. <grace@software-inc.com>",
- QDateTime(QDate(2006, 12, 31), QTime(17, 03)));
- addMail(model, "Radically new concept", "Grace K. <grace@software- inc.com>",
- QDateTime(QDate(2006, 12, 22), QTime(9, 44)));
- ……
- return model;
- }