c++ - QSortFilterProxyModel 过滤实时数据的问题

标签 c++ qt qtableview qsortfilterproxymodel

我正在使用 qsortfilterproxymodel 来过滤来自 QstandardModel 的数据。我能够在我的测试应用程序中实现此过滤过程,但是当我实时使用它时[集成],它似乎没有按预期工作。

[问题]:在我的情况下,数据将每 33 毫秒(大约)写入 QstandardModel[sourcemodel] ,这意味着每 1 秒连续 33-36 行,但是当我使用 qsortfilterproxymodel 进行过滤时它没有按照过滤器检查(指定)显示数据,并且我还重写了 qsortfilterproxymodel 的 filterAcceptrows() 方法,只是为了在使用 QMutex 过滤和释放源模型之前锁定源模型。但我无法实现实时过滤。

[问题:]filterAcceptRows() 方法中添加新行时,如何仅过滤添加到源模型的新行而不是整个模型?

请帮忙..谢谢

ProxyTest.cpp

#include "proxymodeltest.h"
#include "ui_proxymodeltest.h"

QMutex mutex;
ProxyModelTest::ProxyModelTest(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ProxyModelTest)
{
    ui->setupUi(this);

    secondtext = "SECOND";
    firstText = "FIRST";
    regExp = "\\b(" + firstText + "|" + secondtext + ")\\b";

    model = new QStandardItemModel();
    proxyModel = new MySortFilterProxyModel();
    proxyModel->setFilterRegExp(regExp);
    ui->tableView->setModel(proxyModel);
    proxyModel->setSourceModel(model);

    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(updateTable()));
    connect(proxyModel,SIGNAL(rowsInserted(QModelIndex,int,int)),this,
                         SLOT(checkInserted(QModelIndex,int,int)));
    timer->start(25);

}

ProxyModelTest::~ProxyModelTest()
{
    delete ui;
}

void ProxyModelTest::updateTable()
{
    static int count = 0;
    model->insertRow(0,new QStandardItem(""));
    for(int col = 0; col < 4 ;col++)
    {
        model->setItem(0,col,new QStandardItem(""));

        if( count % 2 == 0)
            model->item(0,col)->setBackground(QBrush(QColor("yellow")));
        else
            model->item(0,col)->setBackground(QBrush(QColor("lightGreen")));
    }

    if( count % 2 == 0)
    {
        model->item(0,0)->setText("FIRST");
        model->item(0,1)->setText("some text");
        model->item(0,2)->setText("some text");
        model->item(0,3)->setText("some text");
    }
    else
    {
        model->item(0,0)->setText("SECOND");
        model->item(0,1)->setText("some text");
        model->item(0,2)->setText("some text");
        model->item(0,3)->setText("some text");
    }
    count++;
}

void ProxyModelTest::on_firstCheck_toggled(bool checked)
{
    if(checked)
    {
        firstText = "FIRST";
    }
    else
    {
        firstText = "---";
    }
    regExp = "\\b(" + firstText + "|" + secondtext + ")\\b";
    qDebug() << regExp;
    proxyModel->setFilterRegExp(regExp);
}

void ProxyModelTest::on_checkSecond_toggled(bool checked)
{
    if(checked)
    {
        secondtext = "SECOND";
    }
    else
    {
        secondtext = "---";
    }
    regExp = "\\b(" + firstText + "|" + secondtext + ")\\b";
    proxyModel->setFilterRegExp(regExp);
}

void ProxyModelTest::checkInserted(QModelIndex index, int a, int b)
{
    qDebug() <<"in checkInserted";
}

MySortFilterProxyModel::MySortFilterProxyModel(QObject *parent)
    : QSortFilterProxyModel(parent)
{
}
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
        const QModelIndex &sourceParent) const
{
    bool status;
    mutex.lock();
    QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
    //QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent);
    //QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent);
    qDebug() <<"in filter Accept rows";
    status = sourceModel()->data(index0).toString().contains(filterRegExp());
    mutex.unlock();
    return status;
}

void ProxyModelTest::on_pushButton_clicked()
{
    timer->stop();
}

ProxyTest.h

#ifndef PROXYMODELTEST_H
#define PROXYMODELTEST_H

#include <QMainWindow>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QTimer>
#include <QDebug>
#include <QMutex>
namespace Ui {
class ProxyModelTest;
}

class MySortFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT

public:
    MySortFilterProxyModel(QObject *parent = 0);

protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE;

private:
    bool dateInRange(const QDate &date) const;

};

class ProxyModelTest : public QMainWindow
{
    Q_OBJECT

public:
    explicit ProxyModelTest(QWidget *parent = 0);
    ~ProxyModelTest();

private slots:
    void updateTable();
    void on_firstCheck_toggled(bool checked);

    void on_checkSecond_toggled(bool checked);
    void checkInserted(QModelIndex index,int a,int b);

    void on_pushButton_clicked();

private:
    Ui::ProxyModelTest *ui;
    QStandardItemModel *model;
    MySortFilterProxyModel *proxyModel;
    QString firstText,secondtext,regExp;
    QTimer *timer;
};


#endif // PROXYMODELTEST_H

[更新2]

proxyModelTest.ui

 <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>ProxyModelTest</class>
     <widget class="QMainWindow" name="ProxyModelTest">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>639</width>
        <height>399</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>ProxyModelTest</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <widget class="QTableView" name="tableView">
        <property name="geometry">
         <rect>
          <x>10</x>
          <y>30</y>
          <width>481</width>
          <height>301</height>
         </rect>
        </property>
       </widget>
       <widget class="QPushButton" name="pushButton">
        <property name="geometry">
         <rect>
          <x>550</x>
          <y>200</y>
          <width>75</width>
          <height>23</height>
         </rect>
        </property>
        <property name="text">
         <string>PushButton</string>
        </property>
       </widget>
       <widget class="QWidget" name="layoutWidget">
        <property name="geometry">
         <rect>
          <x>510</x>
          <y>60</y>
          <width>111</width>
          <height>81</height>
         </rect>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout">
         <item>
          <widget class="QCheckBox" name="firstCheck">
           <property name="text">
            <string>First</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QCheckBox" name="checkSecond">
           <property name="text">
            <string>second</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>639</width>
         <height>21</height>
        </rect>
       </property>
      </widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarArea</enum>
       </attribute>
       <attribute name="toolBarBreak">
        <bool>false</bool>
       </attribute>
      </widget>
      <widget class="QStatusBar" name="statusBar"/>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>

最佳答案

我无法编译您的代码(缺少ui_proxymodeltest.h),但我创建了一个可重现的示例,您可能会发现对此有用。

我的过滤代理故意很简单 - 它只传递所有五的倍数的项目:

#include <QSortFilterProxyModel>
class OneInFiveProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT
public:
    OneInFiveProxyModel(QObject *parent = nullptr);
protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE;
};

OneInFiveProxyModel::OneInFiveProxyModel(QObject *parent)
    : QSortFilterProxyModel(parent)
{
}

bool OneInFiveProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
    return sourceModel()->index(sourceRow, 0, sourceParent).data(Qt::UserRole).toInt() % 5 == 0;
}

这是一个简单的类,它将发出我们想要放入模型中的数据:

class Ticker : public QObject
{
    Q_OBJECT
    const int count;
public:
    Ticker(int count, QObject *parent = 0);
public slots:
    void run();
signals:
    void tick(int);
    void finished();
};

#include <QThread>
Ticker::Ticker(int count, QObject *parent)
    : QObject(parent),
      count(count)
{
}

void Ticker::run() {
    for (int i = 0;  i < count;  ++i) {
        QThread::msleep(25);
        emit tick(i);
    }
    emit finished();
}

现在,让我们将它们放入应用程序中。我们将在线程内运行一次股票代码,然后在其自己的线程中再次运行:

#include <QCoreApplication>
#include <QDebug>
#include <QStandardItemModel>

int main(int argc, char **argv)
{
    QCoreApplication app(argc, argv);
    QStandardItemModel model;
    OneInFiveProxyModel proxy;
    proxy.setSourceModel(&model);

    Ticker t(25);
    QObject::connect(&t, &Ticker::tick, &model, [&model](int i){
            auto item = new QStandardItem{QString::number(i)};
            item->setData(i, Qt::UserRole);
            model.appendRow(item);
        });

    // run it in this thread
    t.run();
    qDebug() << "After first run, model contains" << model.rowCount() << "items"
             << "and proxy contains" << proxy.rowCount() << "items";

    // run it again, but in a different thread
    QThread thread;
    t.moveToThread(&thread);
    QObject::connect(&thread, &QThread::started, &t, &Ticker::run);
    QObject::connect(&t, &Ticker::finished, &thread, &QThread::quit);
    QObject::connect(&thread, &QThread::finished, &app, &QCoreApplication::quit);
    thread.start();
    app.exec();  // will return when the thread finishes

    qDebug() << "After second run, model contains" << model.rowCount() << "items"
             << "and proxy contains" << proxy.rowCount() << "items";
}

运行此命令,我每次都会在模型中获得 25 个项目,其中 5 个通过代理可见:

After first run, model contains 25 items and proxy contains 5 items
After second run, model contains 50 items and proxy contains 10 items

需要注意的几点,可能会对您有所帮助:

  • 模型和代理位于同一线程中。这是至关重要的,这样代理就可以访问源模型而无需锁定
  • 我们使用信号来发送要添加到源模型的数据。因此,这些数据的发起者不需要与模型位于同一线程中。
  • 当我向 filterAcceptsRow 添加调试行时,我可以确认每个添加的项目仅调用一次该调试行。

关于c++ - QSortFilterProxyModel 过滤实时数据的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37235743/

相关文章:

c++ - C++中使用全局指针实现红黑树

c++ - 尝试/捕获 C++ 类构造函数的 "in the middle"

qt - 在Windows上使用MinGW编译Poco

python - QFileSystemModel QTableView 日期修改突出显示

python - 上一个问题 PySide2 QListView 和 QTableView 的新功能

c++ - QT FontMetrics::BoundingRect 大小错误

c++ - 循环写入文件时遇到问题

c++ - CGAL:将商转换为 double

c++ - QComboBox 文本颜色没有按预期更改

c++ - Qt 旋转图像 -> 多边形