簡體   English   中英

Qt-如何為QProgressBar結合QtConcurrent和QThreadPool?

[英]Qt - How to combine QtConcurrent and QThreadPool for a QProgressBar?

mainwindow.ui我創建了一個名為progressBarQProgressBar和一個名為speckleQPushButton ,它們開始了繁重的計算。

mainwindow.h內部,我有一個用於按鈕的private slot和一個表示大量計算的專用功能。 mainwindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_speckle_clicked();
    ...

private:
    Ui::MainWindow *ui;
    QFutureWatcher<std::vector<cv::Mat>> futureWatcher;
    std::vector<cv::Mat> progressSpecle();//heavy computation

};

futureWatcher應該監視QtConcurrent返回的QFuture對象:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ...
    connect(&this->futureWatcher, SIGNAL(progressValueChanged(int)), ui->progressBar, SLOT(setValue(int)));
    ...
}

...

void MainWindow::on_speckle_clicked()
{    
    //Start the computation.
    QFuture<std::vector<cv::Mat>> future;
    future = QtConcurrent::run(this, &MainWindow::progressSpecle);
    this->futureWatcher.setFuture(future);

    QThreadPool::globalInstance()->waitForDone();

    vector<cv::Mat> result = future.result();

    specklevisualization *s = new specklevisualization;
    s-> setAttribute(Qt::WA_DeleteOnClose);
    s-> start(result);
    s-> show();
}

但是應用程序不能那樣工作。 編譯並單擊斑點后mainwindow沒有響應。 這是在其中創建x線程的progressSpecle成員函數:

void MainWindow::progressSpecle(){
    vector<cv::Mat> input;
    ...//do something with input

    vector<cv::Mat> result;
    vector<cv::Mat> *all;
    all = &result;

   QThreadPool *threadPool = QThreadPool::globalInstance();

    for(unsigned int i = 1; i<input.size(); i++) {
        cv_speckle_algorithm *work = new cv_speckle_algorithm(input.at(i-1), input.at(i), all, i-1);
        work->setAutoDelete(false);
        threadPool->start(work);
    }

    while(true){
        if(threadPool->activeThreadCount() == 1) return result;
    }

}

該應用程序可以正常運行,但mainWindow不負責,因為(我認為) while(true) 但是我不明白為什么這應該阻塞mainWindow,因為整個progressSpecle函數在一個單獨的線程中工作,該線程是通過QtConcurrent創建和啟動的。

為什么progressSpecle函數會阻止mainWindow? 那么如何使progressBar正常工作?

QFutureWatcher信號從池化線程中發出。 這意味着將通過“排隊連接”調用QProgressBar插槽:一個事件將排隊進入主線程的事件循環,並且在處理此事件時將調用該插槽。

QThreadPool::waitForDone的調用正在阻止主線程,因此事件循環未運行,並且不會調用排隊的插槽。 您需要在等待並發任務完成的同時保持主線程的事件循環運行。

我可以通過兩種方法來實現這一目標。 第一種是將回調連接到QFutureWatcher::finished信號,並將控制權返回到主事件循環:

void MainWindow::on_speckle_clicked()
{
    //Start the computation.
    QFuture<std::vector<cv::Mat>> future;
    future = QtConcurrent::run(this, &MainWindow::progressSpecle);

    connect(&futureWatcher, &QFutureWatcherBase::finished, this, [result] {
        vector<cv::Mat> result = future.result();
        specklevisualization *s = new specklevisualization;
        s->setAttribute(Qt::WA_DeleteOnClose);
        s->start(result);
        s->show();
    });
    this->futureWatcher.setFuture(future);

    // return control to event loop
}

如果願意,可以使用命名方法而不是lambda。

第二種方法是在函數內部運行一個嵌套的事件循環,並將其quit槽連接到QFutureWatcher::finished信號:

void MainWindow::on_speckle_clicked()
{
    QEventLoop localLoop;

    //Start the computation.
    QFuture<std::vector<cv::Mat>> future;
    future = QtConcurrent::run(this, &MainWindow::progressSpecle);

    connect(futureWatcher, &QFutureWatcherBase::finished, &localLoop, &QEventLoop::quit);
    this->futureWatcher.setFuture(future);

    localLoop.exec(); // wait for done

    vector<cv::Mat> result = future.result();
    specklevisualization *s = new specklevisualization;
    s->setAttribute(Qt::WA_DeleteOnClose);
    s->start(result);
    s->show();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM