筛选实时数据时出现QSortFilterProxyModel问题

QSortFilterProxyModel issue in filtering Real Time Data

本文关键字:QSortFilterProxyModel 问题 实时 数据 筛选      更新时间:2023-10-16

我正在使用qsortfilterfroxymodel从QstandardModel中筛选数据。我能够在我的测试应用程序中实现这个过滤过程,但当我实时[集成]使用它时,它似乎没有按预期工作。

[问题]:在我的情况下,数据将每33ms(大约)写入一个QstandardModel[sourcemodel],这意味着连续每1秒33-36行,但是,当我使用qsortfilterfroxymodel进行过滤时,它没有按照检查(指定)的过滤器显示数据,而且我还重写了qsortfilterproxymode的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();
}

现在,让我们把它们放到一个应用程序中。我们将在线程中运行一次ticker,然后在它自己的线程中再次运行:

#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个:

第一次运行后,模型包含25项,代理包含5项
第二次运行后,模型包含50个项目,代理包含10个项目

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

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