IMA*_*N4K 5 qt qtableview qt5 qsortfilterproxymodel
我们QSortFilterProxyModel
在QTableView
和上安装了一个(两个或多个)QLineEdit
以过滤视图(基于这些QLineEdit
的文本)
在我们看来,我们有一个插槽可以告诉我们lineedits字符串和所需的当前列。像这样的东西:
void onTextChange(int index, QString ntext) {
filter.setFilterKeyColumn(index);
filter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive));
}
Run Code Online (Sandbox Code Playgroud)
在第一列中,我们有生日,第二列中,有名字。
现在,我们为第2列输入年份(例如1985)。到目前为止,过滤还可以,但是当我们切换到第一个lineedit并输入名称(例如john)时,基于年份的先前过滤将重置。
我们如何改变这种习俗的行为QSortFilterProxyModel
?
(实际上,当我们更改过滤器键列时,filtermodel必须过滤现有视图而不重置它)
根据@Mike的回答:如果您与未知的列数进行交互,QMap<int, QRegExp>
将有助于您
基于@Hayt 的回答和评论。由于您希望在模型上有两个单独的过滤器,因此您可以有两个链接的过滤器QSortFilterProxyModel
(一个根据名称进行过滤,另一个根据年份进行过滤,使用第一个过滤模型作为源模型)。
这是一个完整的示例,说明如何为一个表设置两个单独的过滤器:
#include <QApplication>
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set up GUI
QWidget w;
QVBoxLayout layout(&w);
QHBoxLayout hLayout;
QLineEdit lineEditName;
QLineEdit lineEditYear;
lineEditName.setPlaceholderText("name filter");
lineEditYear.setPlaceholderText("year filter");
lineEditYear.setValidator(new QRegExpValidator(QRegExp("[0-9]*")));
lineEditYear.setMaxLength(4);
hLayout.addWidget(&lineEditName);
hLayout.addWidget(&lineEditYear);
QTableView tableView;
layout.addLayout(&hLayout);
layout.addWidget(&tableView);
//set up models
QStandardItemModel sourceModel;
QSortFilterProxyModel yearFilterModel;
yearFilterModel.setSourceModel(&sourceModel);
QSortFilterProxyModel nameFilterModel;
//nameFilterModel uses yearFilterModel as source
nameFilterModel.setSourceModel(&yearFilterModel);
//tableView displayes the last model in the chain nameFilterModel
tableView.setModel(&nameFilterModel);
nameFilterModel.setFilterKeyColumn(0);
yearFilterModel.setFilterKeyColumn(1);
nameFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
yearFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
QObject::connect(&lineEditName, &QLineEdit::textChanged, &nameFilterModel,
static_cast<void (QSortFilterProxyModel::*)(const QString&)>
(&QSortFilterProxyModel::setFilterRegExp));
QObject::connect(&lineEditYear, &QLineEdit::textChanged, &yearFilterModel,
static_cast<void (QSortFilterProxyModel::*)(const QString&)>
(&QSortFilterProxyModel::setFilterRegExp));
//fill with dummy data
QVector<QString> names{"Danny", "Christine", "Lars",
"Roberto", "Maria"};
for(int i=0; i<100; i++){
QList<QStandardItem*> row;
row.append(new QStandardItem(names[i%names.size()]));
row.append(new QStandardItem(QString::number((i%9)+1980)));
sourceModel.appendRow(row);
}
w.show();
return a.exec();
}
Run Code Online (Sandbox Code Playgroud)
您可以子类化QSortFilterProxyModel
, 使其采用两个单独的过滤器(一个用于名称,另一个用于年份),并覆盖filterAcceptsRow
以true
仅在两个过滤器都满足时返回。
Qt 文档的自定义排序/过滤器模型示例显示了一个子类QSortFilterProxyModel
,除了用于搜索的主字符串过滤器之外,它还可以采用日期过滤器。
这是一个关于如何使子类QSortFilterProxyModel
为一个表应用两个单独过滤器的完整示例:
#include <QApplication>
#include <QtWidgets>
class NameYearFilterProxyModel : public QSortFilterProxyModel{
Q_OBJECT
public:
explicit NameYearFilterProxyModel(QObject* parent= nullptr):
QSortFilterProxyModel(parent){
//general parameters for the custom model
nameRegExp.setCaseSensitivity(Qt::CaseInsensitive);
yearRegExp.setCaseSensitivity(Qt::CaseInsensitive);
yearRegExp.setPatternSyntax(QRegExp::RegExp);
nameRegExp.setPatternSyntax(QRegExp::RegExp);
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override{
QModelIndex nameIndex= sourceModel()->index(sourceRow, 0, sourceParent);
QModelIndex yearIndex= sourceModel()->index(sourceRow, 1, sourceParent);
QString name= sourceModel()->data(nameIndex).toString();
QString year= sourceModel()->data(yearIndex).toString();
return (name.contains(nameRegExp) && year.contains(yearRegExp));
}
public slots:
void setNameFilter(const QString& regExp){
nameRegExp.setPattern(regExp);
invalidateFilter();
}
void setYearFilter(const QString& regExp){
yearRegExp.setPattern(regExp);
invalidateFilter();
}
private:
QRegExp nameRegExp;
QRegExp yearRegExp;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set up GUI
QWidget w;
QVBoxLayout layout(&w);
QHBoxLayout hLayout;
QLineEdit lineEditName;
QLineEdit lineEditYear;
lineEditName.setPlaceholderText("name filter");
lineEditYear.setPlaceholderText("year filter");
lineEditYear.setValidator(new QRegExpValidator(QRegExp("[0-9]*")));
lineEditYear.setMaxLength(4);
hLayout.addWidget(&lineEditName);
hLayout.addWidget(&lineEditYear);
QTableView tableView;
layout.addLayout(&hLayout);
layout.addWidget(&tableView);
//set up models
QStandardItemModel sourceModel;
NameYearFilterProxyModel filterModel;;
filterModel.setSourceModel(&sourceModel);
tableView.setModel(&filterModel);
QObject::connect(&lineEditName, &QLineEdit::textChanged,
&filterModel, &NameYearFilterProxyModel::setNameFilter);
QObject::connect(&lineEditYear, &QLineEdit::textChanged,
&filterModel, &NameYearFilterProxyModel::setYearFilter);
//fill with dummy data
QVector<QString> names{"Danny", "Christine", "Lars",
"Roberto", "Maria"};
for(int i=0; i<100; i++){
QList<QStandardItem*> row;
row.append(new QStandardItem(names[i%names.size()]));
row.append(new QStandardItem(QString::number((i%9)+1980)));
sourceModel.appendRow(row);
}
w.show();
return a.exec();
}
#include "main.moc"
Run Code Online (Sandbox Code Playgroud)