2016-10-13 163 views
0

在此之前,我询问a question关于我们需要表示多个列过滤,以表示适合多个过滤器模式的行。在处理近乎庞大的数据集时加快QSortFilterProxyModel过滤

现在,当处理大表(通过big我的意思是大约200,000行和4列),如果我们有一个大的表(通常这是过滤器模式的前2个字符中最差),过滤会变得很慢。

那么你对此有何建议?

注:我有自己的高性能源数据模型基于this例如巫喂约1秒

编辑1

我的该行数的视场改变我的方法(而不是QStandardItemModel)从这个:

bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { 
if (/* filtering is enable*/) { 
    bool _res = sourceModel()->data(sourceModel()->index(source_row, 0, source_parent)).toString().contains(/*RegExp for column 0*/); 
    for (int col = 0; col < columnCount(); col++) { 
     _res &= sourceModel()->data(sourceModel()->index(source_row, col + 1, source_parent)).toString().contains(/*RegExp for column col + 1*/); 
    } 
    return _res; 
} 
return true; 

}

要这样:

bool DataFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { 
    if (_enable) { 
     return (sourceModel()->index(source_row, 0, source_parent.child(source_row, 0)).data().toString().contains(/*string for column 0*/)) 
      && sourceModel()->index(source_row, 1, source_parent.child(source_row, 1)).data().toString().contains(/*string for column 1*/)) 
      && sourceModel()->index(source_row, 2, source_parent.child(source_row, 2)).data().toString().contains(/*string for column 2*/)) 
      && sourceModel()->index(source_row, 3, source_parent.child(source_row, 3)).data().toString().contains(/*string for column 3*/)); 
    } 
    return true; 
} 

查找工作Perfect.Now过滤工作就像一个魅力无延迟

+1

1.剖析模型性能。 2.不要使用正则表达式进行过滤,编写自己的方法。 3.如果您确实需要大数据支持 - 请将内存中的SQLite作为模型和过滤的来源。 –

+0

您可以抛弃QSortFilterProxyModel并将其替换为您自己的专用构建实现;由于您知道您的应用程序的特定需求,因此您可能可以将您的实现设计为比QSortFilterProxyModel更高效,而QSortFilterProxyModel必须是通用的,并且不能对与其交互的代码的行为作出任何假设。 –

+0

@ JeremyFriesner.So你说我们应该忘记'QSortFilterProxyModel'.如果我们只需要过滤,在源数据模型(从QAbstractTableModel派生)中实现过滤是否是个好主意?如果没有,我会听你的建议。 – IMAN4K

回答

1

如果项目的数量是非常高的,你不能一次性加载它们,你可以尝试分批只有当添加项目他们需要在视图中。这可以通过覆盖canFetchMore()fetchMore()来完成。看看Fetch More Example。请注意,这是QSqlQueryModel从数据库内部加载大型模型的方式,请参阅here

下面是你的模型可以使用这种方法来实现:

#include <QApplication> 
#include <QtWidgets> 

class MyTableModel : public QAbstractTableModel{ 
public: 
    explicit MyTableModel(int rowCount, QObject* parent=nullptr) 
     :QAbstractTableModel(parent),currentRowCount(0),wholeRowCount(rowCount){} 
    ~MyTableModel(){} 

    int rowCount(const QModelIndex &parent) const override{ 
     if(parent.isValid()) return 0; 
     return currentRowCount; 
    } 
    int columnCount(const QModelIndex &parent) const override{ 
     if(parent.isValid()) return 0; 
     return 2; 
    } 

    QVariant data(const QModelIndex &index, int role) const override{ 
     Q_ASSERT(index.row()<currentRowCount); 
     QVariant val; 
     if(role== Qt::DisplayRole || role== Qt::EditRole){ 
      switch(index.column()){ 
      case 0: 
       val= QString("#%1").arg(index.row()+1, 8, 10, QChar('0')); 
       break; 
      case 1: 
       val= rows[index.row()]; 
       break; 
      } 
     } 
     return val; 
    } 

    bool canFetchMore(const QModelIndex &parent) const override{ 
     if(parent.isValid()) return false; 
     return (currentRowCount < wholeRowCount); 
    } 

    void fetchMore(const QModelIndex& /* index */) override{ 
     int toFetch= qMin(52, wholeRowCount-currentRowCount); 
     char ch = 'A'; 
     beginInsertRows(QModelIndex(), currentRowCount, currentRowCount+toFetch-1); 
     for(int i=0; i<toFetch; i++){ 
      rows+= QString(QChar(ch)); 
      if(ch == 'Z') ch = 'A'; 
      else ch++; 
     } 
     currentRowCount+= toFetch; 
     endInsertRows(); 
    } 

private: 
    int currentRowCount; 
    int wholeRowCount; 
    QStringList rows; 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    QWidget w; 
    QVBoxLayout layout(&w); 
    QLineEdit filterLineEdit; 
    QTableView tableView; 
    layout.addWidget(&filterLineEdit); 
    layout.addWidget(&tableView); 

    MyTableModel model(200000); 
    QSortFilterProxyModel proxyModel; 
    proxyModel.setSourceModel(&model); 
    proxyModel.setFilterKeyColumn(-1); 
    tableView.setModel(&proxyModel); 

    QObject::connect(&filterLineEdit, &QLineEdit::textChanged, [&](){ 
     proxyModel.setFilterFixedString(filterLineEdit.text()); 
    }); 

    w.show(); 

    return a.exec(); 
} 

如果你确定你真正的瓶颈是过滤,你可能还需要通过@DmitrySazonov,子类QSortFilterProxyModel注意避免使用正则表达式,覆盖filterAcceptsRow()并提供您的算法,而不是使用基于通用QRegExp的过滤器。

要考虑的另一件事是避免在筛选器变窄时检查已经过滤的行,看看this question

+0

我很欣赏你的答案。但我很确定我的模型运行良好,我实现了快速的内部结构,并且我可以在一秒内载入200k行(在'release'配置中)。在此期间,我将显示一个不需要分页的进度条。我现在的问题是使用'QSortFilterProxyModel'实时过滤。请您解释一下关于'算法而不是基于QRegExp的过滤器'是不是比较字符串? – IMAN4K

+0

如何在此期间显示进度栏?如果您的模型正在主线程中加载,则在控制返回到事件循环(加载完成时)之前,无法更新进度栏。我认为你做错了什么。 – Mike

+0

@ IMAN4K,我的意思是为'filterAcceptsRow()'提供一个自定义的实现,它不依赖于正则表达式(相反,由于您的特定类型的过滤,它的效果更好)。不过,我真的认为Qt中的正则表达式已经很好地优化了,除非您确定您的过滤具有与正常字符串/正则表达式匹配不同的特定需求,否则您不应该这样做。 – Mike