界面开发框架Qt新手入门 - 自定义排序/筛选模型示例(一)

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()很简单,在头文件中作为内联函数实现。

这就完成了我们的自定义代理模型,接下来的文章将介绍如何在应用程序中使用它。

Qt自定义Model/View模型,您可以继承QAbstractItemModel类,并实现其相关的虚拟函数来定义自己的数据模型。 下面是一个简单的示例,展示如何自定义一个简单的树形模型(Tree Model): ```cpp #include <QAbstractItemModel> #include <QModelIndex> #include <QVariant> class MyTreeModel : public QAbstractItemModel { public: explicit MyTreeModel(QObject *parent = nullptr); ~MyTreeModel(); // 重写父类的虚拟函数 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; }; MyTreeModel::MyTreeModel(QObject *parent) : QAbstractItemModel(parent) { // 在构造函数中初始化数据模型 } MyTreeModel::~MyTreeModel() { // 在析构函数中清理数据 } QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent) const { // 返回指定行、列和父索引的模型索引 } QModelIndex MyTreeModel::parent(const QModelIndex &child) const { // 返回指定子索引的父索引 } int MyTreeModel::rowCount(const QModelIndex &parent) const { // 返回指定父索引的子项数目 } int MyTreeModel::columnCount(const QModelIndex &parent) const { // 返回模型的列数 } QVariant MyTreeModel::data(const QModelIndex &index, int role) const { // 返回指定模型索引和角色的数据 } ``` 在这个示例中,我们自定义了一个名为MyTreeModel的树形模型,继承自QAbstractItemModel类,并重写了QAbstractItemModel的一些虚拟函数。在这些函数中,您可以根据自己的数据结构和需求来实现相应的逻辑。 要使用自定义模型,您可以在视图中设置该模型,如: ```cpp MyTreeModel model; QTreeView view; view.setModel(&model); ``` 当您设置了自定义模型后,视图将使用模型提供的数据来显示和管理数据。 当然,这只是一个简单的示例。在实际应用中,您可能需要更复杂的数据结构和逻辑来实现您的自定义模型。但是通过继承QAbstractItemModel类,并实现其虚拟函数,您可以很好地控制自己的数据模型和视图之间的交互。 希望这个示例能够帮助您开始自定义Model/View模型开发!如果您有任何进一步的问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值