gpt4 book ai didi

c++ - 如果过滤器严格变窄,避免对 QSortFilterProxyModel::filterAcceptsRow() 的冗余调用

转载 作者:可可西里 更新时间:2023-11-01 16:06:29 32 4
gpt4 key购买 nike

有什么方法可以使 QSortFilterProxyModel 中的过滤器无效,但表明过滤器已缩小范围,因此应仅在当前可见的行上调用 filterAcceptsRow()

目前 Qt 不这样做。当我调用 QSortFilterProxyModel::invalidateFilter() 时,我的过滤器从“abcd”更改为“abcde”,创建了一个全新的映射,并且 filterAcceptsRow() 是调用所有源行,即使很明显到目前为止隐藏的源行将保持隐藏状态。

这是来自 QSortFilterProxyModelPrivate::create_mapping() 中 Qt 源代码的代码,它调用了我重写的 filterAcceptsRow(),它创建了一个全新的 Mapping 并遍历所有源行:

Mapping *m = new Mapping;

int source_rows = model->rowCount(source_parent);
m->source_rows.reserve(source_rows);
for (int i = 0; i < source_rows; ++i) {
if (q->filterAcceptsRow(i, source_parent))
m->source_rows.append(i);
}

我想要的是仅迭代映射中的可见行并仅对它们调用 filterAcceptsRow()。如果某行已经被隐藏,则不应对其调用 filterAcceptsRow(),因为我们已经知道它会为其返回 false(过滤器变得更加严格,它并没有松动)。

由于我已经覆盖了 filterAcceptsRow(),Qt 无法知道过滤器的性质,但是当我调用 QSortFilterProxyModel::invalidateFilter() 时,我有有关过滤器是否严格变窄的信息,因此我可以将该信息传递给 Qt(如果它有接受它的方式)。

另一方面,如果我将过滤器从 abcd 更改为 abce,那么应该在所有源行上调用过滤器,因为它已变得严格更窄。

最佳答案

我写了一个QIdentityProxyModel存储链式 QSortFilterProxyModel 列表的子类。它提供了一个类似于 QSortFilterProxyModel 的接口(interface),并接受一个 narrowedDown bool 参数,该参数指示过滤器是否正在缩小范围。这样:

  • 当过滤器缩小范围时,一个新的QSortFilterProxyModel 被添加到链中,并且QIdentityProxyModel 切换到代理链末端的新过滤器。
  • 否则,它删除链中的所有过滤器,构造一个新链,其中一个过滤器对应于当前过滤条件。之后,QIdentityProxyModel 切换到代理链中的新过滤器。

这是一个程序,将类与使用普通 QSortFilterProxyModel 子类进行比较:

Demo program screenshot

#include <QtWidgets>

class FilterProxyModel : public QSortFilterProxyModel{
public:
explicit FilterProxyModel(QObject* parent= nullptr):QSortFilterProxyModel(parent){}
~FilterProxyModel(){}

//you can override filterAcceptsRow here if you want
};

//the class stores a list of chained FilterProxyModel and proxies the filter model

class NarrowableFilterProxyModel : public QIdentityProxyModel{
Q_OBJECT
//filtering properties of QSortFilterProxyModel
Q_PROPERTY(QRegExp filterRegExp READ filterRegExp WRITE setFilterRegExp)
Q_PROPERTY(int filterKeyColumn READ filterKeyColumn WRITE setFilterKeyColumn)
Q_PROPERTY(Qt::CaseSensitivity filterCaseSensitivity READ filterCaseSensitivity WRITE setFilterCaseSensitivity)
Q_PROPERTY(int filterRole READ filterRole WRITE setFilterRole)
public:
explicit NarrowableFilterProxyModel(QObject* parent= nullptr):QIdentityProxyModel(parent), m_filterKeyColumn(0),
m_filterCaseSensitivity(Qt::CaseSensitive), m_filterRole(Qt::DisplayRole), m_source(nullptr){
}

void setSourceModel(QAbstractItemModel* sourceModel){
m_source= sourceModel;
QIdentityProxyModel::setSourceModel(sourceModel);
for(FilterProxyModel* proxyNode : m_filterProxyChain) delete proxyNode;
m_filterProxyChain.clear();
applyCurrentFilter();
}

QRegExp filterRegExp()const{return m_filterRegExp;}
int filterKeyColumn()const{return m_filterKeyColumn;}
Qt::CaseSensitivity filterCaseSensitivity()const{return m_filterCaseSensitivity;}
int filterRole()const{return m_filterRole;}

void setFilterKeyColumn(int filterKeyColumn, bool narrowedDown= false){
m_filterKeyColumn= filterKeyColumn;
applyCurrentFilter(narrowedDown);
}
void setFilterCaseSensitivity(Qt::CaseSensitivity filterCaseSensitivity, bool narrowedDown= false){
m_filterCaseSensitivity= filterCaseSensitivity;
applyCurrentFilter(narrowedDown);
}
void setFilterRole(int filterRole, bool narrowedDown= false){
m_filterRole= filterRole;
applyCurrentFilter(narrowedDown);
}
void setFilterRegExp(const QRegExp& filterRegExp, bool narrowedDown= false){
m_filterRegExp= filterRegExp;
applyCurrentFilter(narrowedDown);
}
void setFilterRegExp(const QString& filterRegExp, bool narrowedDown= false){
m_filterRegExp.setPatternSyntax(QRegExp::RegExp);
m_filterRegExp.setPattern(filterRegExp);
applyCurrentFilter(narrowedDown);
}
void setFilterWildcard(const QString &pattern, bool narrowedDown= false){
m_filterRegExp.setPatternSyntax(QRegExp::Wildcard);
m_filterRegExp.setPattern(pattern);
applyCurrentFilter(narrowedDown);
}
void setFilterFixedString(const QString &pattern, bool narrowedDown= false){
m_filterRegExp.setPatternSyntax(QRegExp::FixedString);
m_filterRegExp.setPattern(pattern);
applyCurrentFilter(narrowedDown);
}

private:
void applyCurrentFilter(bool narrowDown= false){
if(!m_source) return;
if(narrowDown){ //if the filter is being narrowed down
//instantiate a new filter proxy model and add it to the end of the chain
QAbstractItemModel* proxyNodeSource= m_filterProxyChain.empty()?
m_source : m_filterProxyChain.last();
FilterProxyModel* proxyNode= newProxyNode();
proxyNode->setSourceModel(proxyNodeSource);
QIdentityProxyModel::setSourceModel(proxyNode);
m_filterProxyChain.append(proxyNode);
} else { //otherwise
//delete all filters from the current chain
//and construct a new chain with the new filter in it
FilterProxyModel* proxyNode= newProxyNode();
proxyNode->setSourceModel(m_source);
QIdentityProxyModel::setSourceModel(proxyNode);
for(FilterProxyModel* node : m_filterProxyChain) delete node;
m_filterProxyChain.clear();
m_filterProxyChain.append(proxyNode);
}
}
FilterProxyModel* newProxyNode(){
//return a new child FilterModel with the current properties
FilterProxyModel* proxyNode= new FilterProxyModel(this);
proxyNode->setFilterRegExp(filterRegExp());
proxyNode->setFilterKeyColumn(filterKeyColumn());
proxyNode->setFilterCaseSensitivity(filterCaseSensitivity());
proxyNode->setFilterRole(filterRole());
return proxyNode;
}
//filtering parameters for QSortFilterProxyModel
QRegExp m_filterRegExp;
int m_filterKeyColumn;
Qt::CaseSensitivity m_filterCaseSensitivity;
int m_filterRole;

QAbstractItemModel* m_source;
QList<FilterProxyModel*> m_filterProxyChain;
};

//Demo program that uses the class

//used to fill the table with dummy data
std::string nextString(std::string str){
int length= str.length();
for(int i=length-1; i>=0; i--){
if(str[i] < 'z'){
str[i]++; return str;
} else str[i]= 'a';
}
return std::string();
}

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set up GUI
QWidget w;
QGridLayout layout(&w);
QLineEdit lineEditFilter;
lineEditFilter.setPlaceholderText("filter");
QLabel titleTable1("NarrowableFilterProxyModel:");
QTableView tableView1;
QLabel labelTable1;
QLabel titleTable2("FilterProxyModel:");
QTableView tableView2;
QLabel labelTable2;
layout.addWidget(&lineEditFilter,0,0,1,2);
layout.addWidget(&titleTable1,1,0);
layout.addWidget(&tableView1,2,0);
layout.addWidget(&labelTable1,3,0);
layout.addWidget(&titleTable2,1,1);
layout.addWidget(&tableView2,2,1);
layout.addWidget(&labelTable2,3,1);

//set up models
QStandardItemModel sourceModel;
NarrowableFilterProxyModel filterModel1;;
tableView1.setModel(&filterModel1);

FilterProxyModel filterModel2;
tableView2.setModel(&filterModel2);

QObject::connect(&lineEditFilter, &QLineEdit::textChanged, [&](QString newFilter){
QTime stopWatch;
newFilter.prepend("^"); //match from the beginning of the name
bool narrowedDown= newFilter.startsWith(filterModel1.filterRegExp().pattern());
stopWatch.start();
filterModel1.setFilterRegExp(newFilter, narrowedDown);
labelTable1.setText(QString("took: %1 msecs").arg(stopWatch.elapsed()));
stopWatch.start();
filterModel2.setFilterRegExp(newFilter);
labelTable2.setText(QString("took: %1 msecs").arg(stopWatch.elapsed()));
});

//fill model with strings from "aaa" to "zzz" (17576 rows)
std::string str("aaa");
while(!str.empty()){
QList<QStandardItem*> row;
row.append(new QStandardItem(QString::fromStdString(str)));
sourceModel.appendRow(row);
str= nextString(str);
}
filterModel1.setSourceModel(&sourceModel);
filterModel2.setSourceModel(&sourceModel);

w.show();
return a.exec();
}

#include "main.moc"

注意事项:

  • 该类仅在过滤器被缩小时提供某种优化,因为链末端新建的过滤器不需要搜索源模型的所有行。
  • 该类取决于用户是否正在缩小过滤器。也就是说,当用户为参数 narrowedDown 传递 true 时,过滤器被假定为当前过滤器的特例(即使事实并非如此)。否则,它的行为与正常的 QSortFilterProxyModel 完全相同,并且可能有一些额外的开销(由于清理旧的过滤器链)。
  • 当过滤器没有被缩小时,类可以进一步优化,以便它在当前过滤器链中查找与当前过滤器相似的过滤器并立即切换到它(而不是删除整个链和开始一个新的)。当用户在末尾过滤器 QLineEdit 中删除一些字符时(即当过滤器从 "abcd" 变回 "abc"时,这可能特别有用,因为您应该已经在带有 "abc" 的链中有了一个过滤器)。但目前,这还没有实现,因为我希望答案尽可能简洁明了。

关于c++ - 如果过滤器严格变窄,避免对 QSortFilterProxyModel::filterAcceptsRow() 的冗余调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39414607/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com