使用QTimer,QThread和进度条

时间:2018-09-03 13:32:48

标签: c++ qt

我想与Ui线程分开使用计算。计算方法-MainWindowМетод的专用插槽。在计算过程中,已计算的数据将逐渐转移到ProgressBar窗口的对象OutputData中。执行计算的线程也是主窗口的字段。

主窗口构造函数,在其中创建线程并将计算的开始连接到线程的开始:

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

calculation = new QThread(this);

settings.setToDefault();
outputData.setToDefault();
calculationDone = false;

connect(calculation, SIGNAL(started()), this, SLOT(calculate()));

ui->results_display->setText("Загрузите <b>параметры</b> и начинайте расчёты!");
}

按钮方法,使用ProgressBar启动线程和模式窗口:

void MainWindow::on_calculate_button_clicked() {
ui->results_display->clear();
ui->results_display2->clear();

calculation->start();

///TODO QProgressDialog

ProgressDialog progressDialog(&outputData, this);
progressDialog.setModal(true);
progressDialog.exec();

if (progressDialog.result() == QDialog::Rejected) {
    calculation->terminate();
    QMessageBox::critical(this, "Результат", "Расчёт был остановлен!");
} else {
    if (progressDialog.result() == QDialog::Accepted) {
        calculation->quit();
        QMessageBox::about(this, "Результат", "Готово!");
        }
    }
}

模态窗口构造函数设置ProgressBar的参数,创建计时器并设置计时器与更新方法之间的连接:

ProgressDialog::ProgressDialog(OutputData *outputData, QWidget *parent) :
QDialog(parent),
ui(new Ui::ProgressDialog) {
ui->setupUi(this);

data = outputData;

ui->quantity_label->setText("0");
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(static_cast<int>(data->outputSettings.aircraftQuantity));

timer = new QTimer(this);
timer->setSingleShot(false);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(50);
}

ProgressBar更新方法:

void ProgressDialog::update() {
unsigned long aircraftsDone = data->results.size() + data->unprocessedAircrafts.size();
ui->progressBar->setValue(static_cast<int>(aircraftsDone));
ui->aircraftQunatityDone_label->setText(QString::number(aircraftsDone));
ui->progressBar->repaint();

if (aircraftsDone == data->outputSettings.aircraftQuantity) {
    accept();
   }
}

当前计算效果很好,但是没有绘制或更新进度信息。

3 个答案:

答案 0 :(得分:1)

这是因为您的_ProductsTable方法未在新线程中调用。

要使用@await Html.PartialAsync("_LeftSidebar") 在新线程中运行任何方法,必须将该方法是其公共插槽的对象(该对象必须从calculate类继承)移动到QThread实例中使用QObject,然后用QThread信号连接您的方法。 在您的情况下,您只需在QObject::moveToThread的{​​{1}}插槽和QThread::started的{​​{1}}信号之间设置连接,那么当您呼叫calculate时便会触发{您在调用MainWindow的同一线程中使用{1}}方法。

要解决此问题,您应该为QThread::started方法创建一个单独的类,然后将该类的对象移至calculation构造函数中的calculation->start()中。

我建议您看一下reference

中的示例

答案 1 :(得分:1)

这些是Rhathin's answerreference的示例代码。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include "calculationworker.h"
#include "progressdialog.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QThread *calculationThread;
    CalculationWorker *calculationWorker;

signals:
    void startCalculation();
    void stopCalculation();

private slots:
    void on_calculate_button_clicked();
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    calculationThread = new QThread( this );
    calculationWorker = new CalculationWorker();

    calculationWorker->moveToThread( calculationThread );

    connect( this, SIGNAL(startCalculation()), calculationWorker, SLOT(calculate()) );
    connect( this, SIGNAL(stopCalculation()), calculationWorker, SLOT(stopCalculation()), Qt::DirectConnection );

    calculationThread->start();
}

MainWindow::~MainWindow()
{
    calculationThread->quit();
    calculationThread->wait();
    delete calculationWorker;
    delete ui;
}

void MainWindow::on_calculate_button_clicked()
{
    ProgressDialog progressDialog( this );
    connect( calculationWorker, SIGNAL(progress(int, int)), &progressDialog, SLOT(progress(int, int)) );
    connect( calculationWorker, SIGNAL(completed()), &progressDialog, SLOT(completed()) );

    emit startCalculation();

    progressDialog.setModal( true );
    progressDialog.exec();

    if ( progressDialog.result() == QDialog::Rejected ) {
        emit stopCalculation();
    } else if ( progressDialog.result() == QDialog::Accepted ) {
        // Accepted
    }
}

calculationworker.h

#ifndef CALCULATIONWORKER_H
#define CALCULATIONWORKER_H

#include <QObject>
#include <QThread> // msleep()

class CalculationWorker : public QObject
{
    Q_OBJECT
public:
    explicit CalculationWorker(QObject *parent = nullptr);

signals:
    void progress( int processed, int quantity );
    void stopped();
    void completed();

public slots:
    void calculate();
    void stopCalculation();

private:
    bool m_stopFlag;
};

#endif // CALCULATIONWORKER_H

calculationworker.cpp

#include "calculationworker.h"

CalculationWorker::CalculationWorker(QObject *parent) : QObject(parent)
{

}

void CalculationWorker::calculate()
{
    m_stopFlag = false;

    int quantity = 1000;
    for ( int i = 0; i < quantity; i++ ) {
        if ( m_stopFlag ) {
            emit stopped();
            return;
        }

        // Do calculation here
        QThread::msleep( 10 );

        emit progress( i, quantity );
    }

    emit completed();
}

void CalculationWorker::stopCalculation()
{
    m_stopFlag = true;
}

progressdialog.h

#ifndef PROGRESSDIALOG_H
#define PROGRESSDIALOG_H

#include <QDialog>

namespace Ui {
class ProgressDialog;
}

class ProgressDialog : public QDialog
{
    Q_OBJECT

public:
    explicit ProgressDialog(QWidget *parent = nullptr);
    ~ProgressDialog();

private:
    Ui::ProgressDialog *ui;

public slots:
    void progress( int processed, int quantity );
    void completed();
};

#endif // PROGRESSDIALOG_H

progressdialog.cpp

#include "progressdialog.h"
#include "ui_progressdialog.h"

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

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

void ProgressDialog::progress(int processed, int quantity)
{
    ui->progressBar->setMaximum( quantity );
    ui->progressBar->setValue( processed );
}

void ProgressDialog::completed()
{
    accept();
}

答案 2 :(得分:0)

这是另一个版本的示例代码,在计算时不会发出进度。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include "calculationworker.h"
#include "progressdialog.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QThread *calculationThread;
    CalculationWorker *calculationWorker;

signals:
    void startCalculation();

private slots:
    void on_calculate_button_clicked();
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    calculationThread = new QThread( this );
    calculationWorker = new CalculationWorker();

    calculationWorker->moveToThread( calculationThread );

    connect( this, SIGNAL(startCalculation()), calculationWorker, SLOT(calculate()) );

    calculationThread->start();
}

MainWindow::~MainWindow()
{
    calculationThread->quit();
    calculationThread->wait();
    delete calculationWorker;
    delete ui;
}

void MainWindow::on_calculate_button_clicked()
{
    ProgressDialog progressDialog( calculationWorker ,this );

    emit startCalculation();

    progressDialog.exec();

    if ( progressDialog.result() == QDialog::Rejected ) {
        // Rejected(Stopped)
    } else if ( progressDialog.result() == QDialog::Accepted ) {
        // Accepted
    }
}

calculationworker.h

#ifndef CALCULATIONWORKER_H
#define CALCULATIONWORKER_H

#include <QObject>
#include <QThread> // msleep()

class CalculationWorker : public QObject
{
    Q_OBJECT
public:
    explicit CalculationWorker(QObject *parent = nullptr);

    int getQuantity();
    int getProcessed();

signals:
    void started();
    void stopped();
    void completed();

public slots:
    void calculate();
    void stopCalculation();

private:
    bool m_stopFlag;
    bool m_stopped;

    int m_processed;
    int m_quantity;
};

#endif // CALCULATIONWORKER_H

calculationworker.cpp

#include "calculationworker.h"

CalculationWorker::CalculationWorker(QObject *parent) : QObject(parent)
{
    m_quantity = 1000;
}

int CalculationWorker::getQuantity()
{
    // Return quantity (data->outputSettings.aircraftQuantity)))
    return m_quantity;
}

int CalculationWorker::getProcessed()
{
    // Return processed (data->results.size() + data->unprocessedAircrafts.size())
    return m_processed;
}

void CalculationWorker::calculate()
{
    m_stopFlag = false;

    emit started();

    // Calculation
    for ( m_processed = 0; m_processed < m_quantity; m_processed++ ) {
        if ( m_stopFlag ) {
            // emit stopped();
            return;
        }

        // Do calculation here
        QThread::msleep( 10 );
    }

    emit completed();
}

void CalculationWorker::stopCalculation()
{
    m_stopFlag = true;
}

progressdialog.h

#ifndef PROGRESSDIALOG_H
#define PROGRESSDIALOG_H

#include <QDialog>
#include <QTimer>
#include "calculationworker.h"

namespace Ui {
class ProgressDialog;
}

class ProgressDialog : public QDialog
{
    Q_OBJECT

public:
    explicit ProgressDialog( CalculationWorker *worker, QWidget *parent = nullptr);
    ~ProgressDialog();

private:
    Ui::ProgressDialog *ui;
    CalculationWorker *m_worker;
    QTimer *m_progressTimer;

public slots:
    void started();
    void update();
};

#endif // PROGRESSDIALOG_H

progressdialog.cpp

#include "progressdialog.h"
#include "ui_progressdialog.h"

ProgressDialog::ProgressDialog( CalculationWorker *worker, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ProgressDialog),
    m_worker(worker),
    m_progressTimer(new QTimer(parent))
{
    ui->setupUi(this);

    // Connect started signal from worker
    connect( m_worker, SIGNAL(started()), this, SLOT(started()) );

    // Stop calculation by clicking reject button
    connect( this, SIGNAL(rejected()), m_worker, SLOT(stopCalculation()), Qt::DirectConnection );

    // Connect timeout signal to update
    connect( m_progressTimer, SIGNAL(timeout()), this, SLOT(update()) );

    // Stop the timer when the dialog is closed
    connect( this, SIGNAL(finished(int)), m_progressTimer, SLOT(stop()) );
}

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

void ProgressDialog::started()
{
    ui->progressBar->setMaximum( m_worker->getQuantity() );
    m_progressTimer->start( 50 );
}

void ProgressDialog::update()
{
    ui->progressBar->setValue( m_worker->getProcessed() );

    if ( m_worker->getProcessed() == m_worker->getQuantity() ) {
        accept();
    }
}