2016-05-15 126 views
1

我正在使用qsortfilterproxymodel来过滤QstandardModel中的数据。我能够在我的测试应用程序中实现这个过滤过程,但是当我在实时使用它[集成]它似乎不工作如预期。QSortFilterProxyModel问题在过滤实时数据

[问题]:在我的情况下数据将被写入到每QstandardModel为33ms(约),这意味着33-36行每1秒连续,但是当我使用qsortfilterproxymodel过滤其未示出的[sourcemodel]数据作为每个筛选器检查(指定),并且我还在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> 
+0

显示您的代码,很难说没有细节。 “我也重写了qsortfilterproxymodel的filterAcceptrows()方法,以便在过滤之前锁定源模型” - 不确定你在锁定方面究竟做了什么,但它听起来并不安全,因为filterAcceptRows()不是唯一的访问需要同步的源模型。 –

+1

显示你的代码,甚至更好,一个MCVE(http://stackoverflow.com/help/mcve) – perencia

+0

抱歉提供更多的信息,因为我不知道格式化代码,所以它花了一些时间:-(.. @ FrankOsterfeld我编辑了我的问题并添加了代码。将来updateTable()将被移动到一个线程。 – pra7

回答

1

我不能编译代码(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可见通过代理:

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

有几点需要注意,并且可以帮助你:

  • 模型和代理生活在同一个线程中。这是至关重要的,以便代理可以访问源模型而不需要任何锁定
  • 我们使用信号来允许我们发送要添加到源模型的数据。所以这些数据的创建者不需要与模型在同一个线程中。
  • 当我添加一条调试线到filterAcceptsRow时,我可以确认它只对每个添加的项目调用一次。
+0

嗨@Toby Speight,谢谢你的帮助。我已经上传了'proxymodeltest.ui',我错过了,请运行它,并启用'filterAcceptRows'中的调试行,你可以看到问题。我会根据你的建议更改代码,并感谢你的意见,请让我知道你对此的看法。 – pra7