C++ 在处理接近大的数据集时,加快QSortFilterProxyModel过滤

C++ 在处理接近大的数据集时,加快QSortFilterProxyModel过滤,c++,qt,qt5,qabstractitemmodel,qsortfilterproxymodel,C++,Qt,Qt5,Qabstractitemmodel,Qsortfilterproxymodel,之前,我问过关于多列过滤的问题,我们需要表示符合多个过滤模式的行 现在,当处理大表时(通过big我的意思是大约200000行和4列),如果我们有一个这么大的表,过滤速度会变慢(通常这对于过滤器模式的前2个字符来说是最差的) 那么你对此有何建议 注意:我有自己的高性能源数据模型(而不是QStandardItemModel),基于示例,在大约1秒的时间内为该行数提供视图 编辑1 从以下内容更改我的方法: bool filterAcceptsRow(int source_row, const QMod

之前,我问过关于多列过滤的问题,我们需要表示符合多个过滤模式的行

现在,当处理大表时(通过
big
我的意思是大约200000行和4列),如果我们有一个这么大的表,过滤速度会变慢(通常这对于过滤器模式的前2个字符来说是最差的)

那么你对此有何建议

注意:我有自己的高性能源数据模型(而不是
QStandardItemModel
),基于示例,在大约1秒的时间内为该行数提供视图

编辑1 从以下内容更改我的方法:

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;

“外观”功能完美无瑕。现在,过滤功能可以像魅力一样毫不延迟地发挥作用

如果项目数量非常多,您无法一次性加载它们,您可以尝试仅在视图中需要时批量添加项目。这可以通过重写和来完成。看一看这张照片。请注意,这就是
QSqlQueryModel
从数据库内部加载大型模型的方式,请参阅

以下是如何使用此方法实现您的模型:

#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();
}
#包括
#包括
类MyTableModel:PublicQAbstractTableModel{
公众:
显式MyTableModel(整数行数,QObject*parent=nullptr)
:QAbstractTableModel(父级)、currentRowCount(0)、wholeRowCount(rowCount){}
~MyTableModel(){}
int rowCount(常量QModelIndex&parent)常量重写{
if(parent.isValid())返回0;
返回当前行计数;
}
int columnCount(常量QModelIndex&parent)常量重写{
if(parent.isValid())返回0;
返回2;
}
QVariant数据(常量QModelIndex&index,int角色)常量覆盖{

Q_断言(index.row()1.分析您的模型性能。2.不要使用regexp进行筛选,编写您自己的方法。3.如果您确实需要大数据支持,请将内存中的SQLite作为模型和筛选的源。您可以放弃QSortFilterProxyModel,用您自己专门构建的实现替换它;因为您知道您的应用程序的特殊需要,您可以e能够设计出比QSortFilterProxyModel更高效的实现,QSortFilterProxyModel必须是通用的,并且不能对与之交互的代码的行为做出任何假设。@JeremyFriesner。所以你说我们应该忘记
QSortFilterProxyModel
。在源数据内部实现过滤是个好主意吗模型(源自
QAbstractTableModel
),如果我们只需要筛选?如果不需要,我将听取您的建议。@DmitrySazonov。如果我是对的,请确认:使用字符串代替RegExp并使用自己的方法(setter)我们设置了过滤字符串?事实上,我从MSSQL中获取数据到我的模型中没有问题,正如我所说,对于200000行来说,它非常快,当我们使用过滤时,数据(该视图使用它)在内存中使用
&&
时,尝试帮助它快速失败-将最不可能的情况放在第一位。这将减少必须评估连接的后续分支的次数。我感谢您的回答。但我非常确定我的模型工作得很好,我使用快速内部结构实现了它,并且我可以加载200k行JUt在一秒钟内(在
release
config中)。在此期间,我显示了一个进度条,无需分页。我现在的问题是使用
QSortFilterProxyModel
进行实时筛选。能否请您解释一下
算法而不是基于QRegExp的筛选器
这不仅仅是比较字符串吗?在此期间如何显示进度条?如果您的模型是在主线程中加载时,只有将控件返回到事件循环(加载完成后)才能更新进度条。我认为您做错了。@IMAN4K,我的意思是为不依赖正则表达式的
filterAcceptsRow()
提供自定义实现(由于您采用了特定的过滤方式,因此效果更好)。然而,我真的认为Qt中的正则表达式得到了很好的优化,你不应该这样做,除非你确定你的筛选有非常特殊的需要,不同于普通的字符串/regexp匹配。@Mike。使用线程:我将在worker对象中运行我的查询,并填充我的结构,结束后我将发出success signal(在这个过程中,视图是隐藏的,并且显示自定义progressbar)当发出成功信号时,我将把我的结构提供给model,然后调用
view::show()
。所有这一切只需1秒钟,不会阻塞主循环。@IMAN4K,在您链接的github存储库中,我找不到线程的任何用途,这就是为什么我问我的问题。那么,您是否正在寻找一种在另一个线程中进行过滤的方法?如果是,您可能想具体询问一个新问题,并提供什么你试过。
#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();
}