Я создал минимальный пример графического интерфейса пользователя QT для обновления виджетов из рабочего потока на основе рекомендуемого подхода в документации QThread 5.12 .
Как описано в документации QThread 5.12 , класс Worker (с потенциально длинным void doWork (const QString & параметр) метод имеет вид:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
и соответствующий класс контроллеров:
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
В отличие от подклассов из QThread
, подход, показанный в документации, показывает рекомендуемый способ, который использует контроллер и рабочий, который расширяет QObject
вместо расширения QThread и переопределяет метод QThread::run
, однако это делает не показывает, как их следует использовать в контексте реального примера.
Мне нужно использовать рабочий поток QT, который обновляет виджеты в графическом интерфейсе с помощью таймера.
Мне также нужно иметь возможность остановить и перезапустить / перезапустить этот поток с другими параметрами, и у меня возникли некоторые проблемы с тем, как сделать это правильно. указывает предпочтительный способ сделать это через контроллер и рабочий, но логика подключения немного сбивает с толку.
Место, где мне нужна помощь, - это как правильно интегрировать таймер в мой рабочий поток, а также как остановить и перезапустить замещающий работник, когда текущий завершает работу, прерывается и перезапускается.
Мой рабочий код состоит из следующих файлов.
controller.h
#pragma once
// SYSTEM INCLUDES
#include <QObject>
#include <QThread>
// APPLICATION INCLUDES
#include "Worker.h"
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller(/*MainWindow* mainWindow*/) {
auto worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &) {
// how do I update the mainWindow from here
}
signals:
void operate(int);
};
Worker.h
#pragma once
// SYSTEM INCLUDES
#include <QTimer>
#include <QObject>
#include <QEventLoop>
// APPLICATION INCLUDES
#include "Worker.h"
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(int count) {
QString result = "finished";
// Event loop allocated in workerThread
// (non-main) thread affinity (as moveToThread)
// this is important as otherwise it would occur
// on the main thread.
QEventLoop loop;
for (auto i=0; i< count; i++) {
// wait 1000 ms doing nothing...
QTimer::singleShot(1000, &loop, SLOT(quit()));
// process any signals emitted above
loop.exec();
emit progressUpdate(i);
}
emit resultReady(result);
}
signals:
void progressUpdate(int secondsLeft);
void resultReady(const QString &result);
};
MainWindow.h - Мне нужно было добавить Controller
член здесь. Я также добавил слот updateValue здесь, где я хочу обновить графический интерфейс. К сожалению, я не знаю, как заставить контроллер или рабочий connect
получить сигнал из потока, чтобы обновить этот слот.
#pragma once
// SYSTEM INCLUDES
#include <memory>
#include <QMainWindow>
// APPLICATION INCLUDES
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
namespace Ui {
class MainWindow;
}
class Controller;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void updateValue(int secsLeft);
private:
Ui::MainWindow *ui;
std::unique_ptr<Controller> mpController;
};
MainWindow.cpp -
#include <QThread>
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "Controller.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, mpController(std::make_unique<Controller>())
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
emit mpController->operate(100);
}
void MainWindow::updateValue(int secsLeft)
{
ui->secondsLeft->setText(QString::number(secsLeft));
}
и, наконец, main.cpp
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Мне в основном нужна помощь и объяснение того, как я должен использовать контроллер / рабочий QT Thread, интегрированный в мой графический интерфейс.