2015-05-11 6 views
1

У меня есть простой объект C++, который запускает процедуру сбора данных в отдельном потоке и уведомляет процесс с сигналом Boost под названием acquisitionStageChangedEvent со следующей подписью: boost::signal2::signal<void(const std::string &)>. Как я могу начать сбор в новом потоке и обновить интерфейс с этой информацией без исключения перекрестных потоков?Как обновить Qt GUI из сигнала Boost, поднятого в другом потоке?

+0

Почему бы не «QTthread» и QT-сигнал? – user3528438

+0

Возможный дубликат http://stackoverflow.com/questions/5050588/how-in-boost-send-a-signal-in-a-thread-and-have-the-corresponding-slot-executed –

ответ

-1

Вот рабочий пример того, как запустить фоновый поток и обновление пользовательского интерфейса во время обновления прогресса и в конце задачи:

namespace Ui 
{ 
    class DtacqAcquisitionWidget; 
} 

class DtacqAcquisitionWidget : public QWidget 
{ 
    Q_OBJECT 

public: 
    explicit AcquisitionWidget(QWidget *parent = 0); 

    ~DtacqAcquisitionWidget(); 

private slots: 

    void on_pushButtonStart_clicked(); 

    void onDtacqChangeState(const QString &stage); 

    /*... Other slots here */ 
private: 
    Ui::AcquisitionWidget *ui; 

    QFutureWatcher<void> *m_future_watcher; // This is to be able to run UI code at the end of the background thread 

    anlytcs::Dt100Acq m_dtacq; // The plain C++ object that raises the boost signal 'acquisitionStageChangedEvent' 
}; 

В файле .cpp:

DtacqAcquisitionWidget::DtacqAcquisitionWidget(QWidget *parent) : 
    QWidget(parent), 
    ui(new Ui::DtacqAcquisitionWidget) 
{ 
    ui->setupUi(this); 

    // Run the 'onAcquisitionFinished' slot at the end of the thread 
    m_future_watcher = new QFutureWatcher<void>(this); 
    connect(m_future_watcher, SIGNAL(finished()), this, SLOT(onAcquisitionFinished())); 

    // Acquisition stages update 
    m_dtacq.acquisitionStageChangedEvent.connect([this](const std::string &stage) 
    { 
     this->onDtacqChangeState(QString::fromStdString(stage)); 
    }); 
} 

void DtacqAcquisitionWidget::on_pushButtonStart_clicked() // Starting the acquisition 
{ 
    ui->pushButtonStop->setEnabled(true); 
    ui->pushButtonStart->setEnabled(false); 
    ui->progressBar->setValue(0); 

    // Start the acquisition in a new thread 
    QFuture<void> f = QtConcurrent::run(this, &DtacqAcquisitionWidget::acquireChannelData);  
    m_future_watcher->setFuture(f); 
} 

void DtacqAcquisitionWidget::onDtacqChangeState(const QString &stage) 
{ 
    if (thread() != QThread::currentThread()) 
    {  
     QMetaObject::invokeMethod(this, "onDtacqChangeState", 
      Qt::BlockingQueuedConnection, Q_ARG(QString, stage)); 
    } 
    else 
    { 
     ui->labelDtacqState->setText(stage); 
     ui->progressBar->setValue(ui->progressBar->value() + 40); 
    }  
} 

void DtacqAcquisitionWidget::onAcquisitionFinished() 
{ 
    // Set what to update here in the GUI here when the acquisition thread finishes  
    ui->labelDtacqState->setText("DONE!"); 
} 

void DtacqAcquisitionWidget::acquireChannelData() 
{ 
    // This is running on a background thread (Non UI thread) 
    double time_sec = ui->spinBoxAcqTimeSec->value(); 
    uint32_t channel_mask = getChannelMask(); 

    std::string data_path = "C:/Users/pardinad/Desktop/DtacqData/"; 
    m_dtacq.startAcquisition(time_sec, channel_mask, 250); 
    ui->labelDtacqState->setText("Acquisition Started!"); 

    if(m_dtacq.completeAcquisition()) 
    { 
     for (auto & dch : m_dtacq.dataChannels()) 
     { 
      std::stringstream ss; 
      ss << data_path << std::setw(2) << std::setfill('0') << dch.channelNumber() << ".DAT"; 
      std::string ch_file = ss.str(); 
      dch.saveToFile(ch_file); 
     } 
    } 
} 
+0

Это довольно грязное решение. Гораздо проще просто сделать объект работника по сбору данных и оставить его в покое. Смешивание сигнала будильника/слота/потока с помощью Qt - это просто неправильная отправная точка. – user3528438

+1

@ user3528438, вы знаете, что не всегда есть выбор, как дела обстоят? Когда-либо работал с устаревшим кодом в платный проект? – Greenflow

+0

@ user3528438 Точка не смешивания boost :: сигналов с сигналами/слотами Qt, а для создания тонкой оболочки Qt UI вокруг кросс-платформенной библиотеки, которая не имеет Qt в качестве зависимости. Я хорошо знаю фразу, которая гласит: «когда в Риме делают то, что делают римляне», но это не так. –

0

Установите std::atomic<bool> на значение true в вашем обработчике сигнала и отметьте этот флаг с QTimer.