Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。
自定义排序/筛选模型示例说明了如何子类化QSortFilterProxyModel来执行高级排序和筛选。
QSortFilterProxyModel类提供了对在另一个模型和视图之间传递的数据进行排序和过滤的支持。
模型通过将它提供的模型索引映射到对应于不同位置的新索引来转换源模型的结构,以供视图使用。这种方法允许对给定的源模型进行视图重构,而不需要对底层数据进行任何转换,也不需要在内存中复制数据。
自定义排序/筛选模型示例由两个类组成:
- MySortFilterProxyModel类提供了一个自定义代理模型。
- Window类提供了主应用程序窗口,使用自定义代理模型对标准项模型进行排序和筛选。
我们将首先查看MySortFilterProxyModel类,了解如何实现自定义代理模型;然后查看Window类,来了解如何使用该模型;最后我们将快速查看main()函数。
点击获取Qt Widget组件下载
MySortFilterProxyModel类定义
MySortFilterProxyModel类继承了QSortFilterProxyModel类。
由于QAbstractProxyModel及其子类派生自QAbstractItemModel,许多关于常规模型子类化的建议也适用于代理模型。
另一方面值得注意的是,QSortFilterProxyModel的许多默认函数实现都是这样编写的,以便它们调用相关源模型中的等效函数。对于具有更复杂行为的源模型,可能需要重写这个简单的代理机制。在本例中,我们从QSortFilterProxyModel类派生出来,以确保我们的过滤器可以识别有效的日期范围,并控制排序操作。
class MySortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
MySortFilterProxyModel(QObject *parent = nullptr);
QDate filterMinimumDate() const { return minDate; }
void setFilterMinimumDate(QDate date);
QDate filterMaximumDate() const { return maxDate; }
void setFilterMaximumDate(QDate date);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
private:
bool dateInRange(QDate date) const;
QDate minDate;
QDate maxDate;
};
我们希望能够通过指定给定的时间段来过滤数据,因此实现了自定义的setFilterMinimumDate()和setFilterMaximumDate()函数,以及相应的filterMinimumDate()和filterMaximumDate()函数。我们重新实现了QSortFilterProxyModel的filterAcceptsRow()函数,来只接受具有有效日期的行,并且QSortFilterProxyModel::lessThan()能够根据发件人的电子邮件地址对其进行排序。最后,实现了一个dateInRange()方便函数,用于确定日期是否有效。
MySortFilterProxyModel类实现
MySortFilterProxyModel构造函数很简单,它将父形参传递给基类构造函数:
MySortFilterProxyModel::MySortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
MySortFilterProxyModel实现中最有趣的部分是QSortFilterProxyModel的filterAcceptsRow()和lessThan()函数的重新实现,让我们首先看一下定制的lessThan()函数。
bool MySortFilterProxyModel::lessThan(const QModelIndex &left,
const QModelIndex &right) const
{
QVariant leftData = sourceModel()->data(left);
QVariant rightData = sourceModel()->data(right);
我们想按发件人的电子邮件地址对他们进行分类,lessThan()函数在排序时用作<操作符。默认实现处理一个类型集合,包括QDateTime和String,但为了能够根据发件人的电子邮件地址进行排序,我们必须首先在给定的字符串中识别地址:
if (leftData.userType() == QMetaType::QDateTime) {
return leftData.toDateTime() < rightData.toDateTime();
} else {
static const QRegularExpression emailPattern("[\\w\\.]*@[\\w\\.]*");
QString leftString = leftData.toString();
if (left.column() == 1) {
const QRegularExpressionMatch match = emailPattern.match(leftString);
if (match.hasMatch())
leftString = match.captured(0);
}
QString rightString = rightData.toString();
if (right.column() == 1) {
const QRegularExpressionMatch match = emailPattern.match(rightString);
if (match.hasMatch())
rightString = match.captured(0);
}
return QString::localeAwareCompare(leftString, rightString) < 0;
}
}
我们使用qregulareexpression为正在寻找的地址定义一个模式,match()函数返回一个QRegularExpressionMatch对象,其中包含匹配结果,如果有匹配,hasMatch()返回true。匹配的结果可以用QRegularExpressionMatch的capture()函数检索,整个匹配的索引为0,括号内的子表达式的索引从1开始(不包括非捕获括号)。
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent);
QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent);
return (sourceModel()->data(index0).toString().contains(filterRegularExpression())
|| sourceModel()->data(index1).toString().contains(filterRegularExpression()))
&& dateInRange(sourceModel()->data(index2).toDate());
}
另一方面,如果给定的行应该包含在模型中,则filterAcceptsRow()函数将返回true。在我们的示例中,如果主题或发送方中有一个包含给定的正则表达式,并且日期有效,则行被接受。
bool MySortFilterProxyModel::dateInRange(QDate date) const
{
return (!minDate.isValid() || date > minDate)
&& (!maxDate.isValid() || date < maxDate);
}
我们使用自定义dateInRange()函数来确定日期是否有效。
为了能够通过指定给定的时间段来过滤数据,我们还实现了获取和设置最小和最大日期的函数:
void MySortFilterProxyModel::setFilterMinimumDate(QDate date)
{
minDate = date;
invalidateFilter();
}
void MySortFilterProxyModel::setFilterMaximumDate(QDate date)
{
maxDate = date;
invalidateFilter();
}
get函数filterMinimumDate()和filterMaximumDate()很简单,在头文件中作为内联函数实现。
这就完成了我们的自定义代理模型,接下来的文章将介绍如何在应用程序中使用它。