Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。
自定义排序/筛选模型示例说明了如何子类化QSortFilterProxyModel来执行高级排序和筛选。
在上文中(点击这里回顾>>),为大家讲解了如何实现MySortFilterProxyModel类、MySortFilterProxyModel的定义,本文将继续讲解Window类的定义和实现!
点击获取Qt Widget组件下载
Window类定义
CustomFilter类继承了QWidget,并提供了这个例子的主应用程序窗口:
class Window : public QWidget
{
Q_OBJECT
public:
Window();
void setSourceModel(QAbstractItemModel *model);
private slots:
void textFilterChanged();
void dateFilterChanged();
private:
MySortFilterProxyModel *proxyModel;
QGroupBox *sourceGroupBox;
QGroupBox *proxyGroupBox;
QTreeView *sourceView;
QTreeView *proxyView;
QLabel *filterPatternLabel;
QLabel *fromLabel;
QLabel *toLabel;
FilterWidget *filterWidget;
QDateEdit *fromDateEdit;
QDateEdit *toDateEdit;
};
我们实现了两个私有槽,textFilterChanged()和dateFilterChanged(),用于响应用户更改过滤器模式、区分大小写或任何日期,此外还实现了一个公共的setSourceModel()方便函数来设置模型/视图关系。
Window类实现
在本示例中,我们选择在main()函数中创建和设置源模型,因此在构建主应用程序窗口时,假设源模型已经存在,并从创建自定义代理模型的实例开始:
Window::Window()
{
proxyModel = new MySortFilterProxyModel(this);
我们设置dynamicSortFilter属性,该属性保存代理模型是否被动态排序和过滤。通过将该属性设置为true,可以确保在源模型的内容发生变化时对模型进行排序和过滤。
主应用程序窗口显示源模型和代理模型的视图,源视图非常简单:
sourceView = new QTreeView;
sourceView->setRootIsDecorated(false);
sourceView->setAlternatingRowColors(true);
QTreeView类提供了树视图的默认模型/视图实现,视图实现了应用程序源模型中项目的树表示。
sourceLayout->addWidget(sourceView);
sourceGroupBox = new QGroupBox(tr("Original Model"));
sourceGroupBox->setLayout(sourceLayout);
QTreeView 类提供了树视图的默认模型/视图实现,视图实现了应用程序源模型中项目的树表示,将视图小部件添加到我们安装在相应组框上的布局中。
另一方面代理模型视图包含几个控件,这些控件控制转换源模型数据结构的各个方面:
filterWidget = new FilterWidget;
filterWidget->setText(tr("Grace|Sports"));
connect(filterWidget, &FilterWidget::filterChanged, this, &Window::textFilterChanged);
filterPatternLabel = new QLabel(tr("&Filter pattern:"));
filterPatternLabel->setBuddy(filterWidget);
fromDateEdit = new QDateEdit;
fromDateEdit->setDate(QDate(1970, 01, 01));
fromLabel = new QLabel(tr("F&rom:"));
fromLabel->setBuddy(fromDateEdit);
toDateEdit = new QDateEdit;
toDateEdit->setDate(QDate(2099, 12, 31));
toLabel = new QLabel(tr("&To:"));
toLabel->setBuddy(toDateEdit);
connect(filterWidget, &QLineEdit::textChanged,
this, &Window::textFilterChanged);
connect(fromDateEdit, &QDateTimeEdit::dateChanged,
this, &Window::dateFilterChanged);
connect(toDateEdit, &QDateTimeEdit::dateChanged,
this, &Window::dateFilterChanged);
请注意,每当用户更改其中一个过滤选项时,我们必须显式地重新应用该过滤器,这是通过将各种编辑器连接到更新代理模型的函数来完成的。
proxyView = new QTreeView;
proxyView->setRootIsDecorated(false);
proxyView->setAlternatingRowColors(true);
proxyView->setModel(proxyModel);
proxyView->setSortingEnabled(true);
proxyView->sortByColumn(1, Qt::AscendingOrder);
QGridLayout *proxyLayout = new QGridLayout;
proxyLayout->addWidget(proxyView, 0, 0, 1, 3);
proxyLayout->addWidget(filterPatternLabel, 1, 0);
proxyLayout->addWidget(filterWidget, 1, 1);
proxyLayout->addWidget(fromLabel, 3, 0);
proxyLayout->addWidget(fromDateEdit, 3, 1, 1, 2);
proxyLayout->addWidget(toLabel, 4, 0);
proxyLayout->addWidget(toDateEdit, 4, 1, 1, 2);
proxyGroupBox = new QGroupBox(tr("Sorted/Filtered Model"));
proxyGroupBox->setLayout(proxyLayout);
排序将由视图处理,我们所要做的就是通过设置QTreeView::sortingEnabled属性(默认为false)来启用代理视图的排序。然后,我们将所有过滤小部件和代理视图添加到安装在相应组框上的布局中。
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(sourceGroupBox);
mainLayout->addWidget(proxyGroupBox);
setLayout(mainLayout);
setWindowTitle(tr("Custom Sort/Filter Model"));
resize(500, 450);
}
最后,在将两个组框放入安装在主应用程序小部件上的另一个布局中之后,自定义应用程序窗口。
如上所述,在main()函数中创建源模型,调用Window::setSourceModel()函数使应用程序使用它:
void Window::setSourceModel(QAbstractItemModel *model)
{
proxyModel->setSourceModel(model);
sourceView->setModel(model);
for (int i = 0; i < proxyModel->columnCount(); ++i)
proxyView->resizeColumnToContents(i);
for (int i = 0; i < model->columnCount(); ++i)
sourceView->resizeColumnToContents(i);
}
QSortFilterProxyModel::setSourceModel()函数使代理模型处理给定模型中的数据,在本例中是邮件模型,视图小部件从QAbstractItemModel 类继承的setModel() 为视图设置要呈现的模型。注意,后一个函数还将创建和设置一个新的选择模型。
void Window::textFilterChanged()
{
FilterWidget::PatternSyntax s = filterWidget->patternSyntax();
QString pattern = filterWidget->text();
switch (s) {
case FilterWidget::Wildcard:
pattern = QRegularExpression::wildcardToRegularExpression(pattern);
break;
case FilterWidget::FixedString:
pattern = QRegularExpression::escape(pattern);
break;
default:
break;
}
QRegularExpression::PatternOptions options = QRegularExpression::NoPatternOption;
if (filterWidget->caseSensitivity() == Qt::CaseInsensitive)
options |= QRegularExpression::CaseInsensitiveOption;
QRegularExpression regularExpression(pattern, options);
proxyModel->setFilterRegularExpression(regularExpression);
}
每当用户更改过滤器模式或区分大小写时,就调用textFilterChanged()函数。
首先检索首选语法(FilterWidget::PatternSyntax enum用于解释给定模式的含义),然后确定首选的大小写敏感性。基于这些参数和当前的过滤器模式,我们设置代理模型的filterRegularExpression 属性。filterRegularExpression 属性保存用于过滤源模型内容的正则表达式,注意调用QSortFilterProxyModel的setfilterregulareexpression()函数也会更新模型。
void Window::dateFilterChanged()
{
proxyModel->setFilterMinimumDate(fromDateEdit->date());
proxyModel->setFilterMaximumDate(toDateEdit->date());
}
每当用户修改有效日期范围时,就调用dateFilterChanged()函数,从用户界面检索新的日期,并调用相应的函数(由自定义代理模型提供)来设置代理模型的最小和最大日期。如上所述,调用这些函数也会更新模型。
Main()函数
在本例中我们通过在main()函数中创建模型,将应用程序与源模型分离开来。首先我们创建应用程序,然后创建源模型:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.setSourceModel(createMailModel(&window));
window.show();
return app.exec();
}
createMailModel()函数是为简化构造函数而提供的方便函数,它所做的就是创建并返回一个描述电子邮件集合的模型。该模型是QStandardItemModel类的一个实例,也就是说,一个用于存储自定义数据的通用模型,通常用作标准Qt数据类型的存储库,每个邮件描述都使用addMail()(另一个方便的函数)添加到模型中。