运行 单独线程上的 QT MainWindow 方法

Running a QT MainWindow method on a separate thread

我正在编写一个 C++ QT5 小部件桌面应用程序,当按下 start/stop 按钮时,我需要在单独的线程上 运行 一个耗时的操作 MainWindow::performLengthyOperation(bool)

这个耗时的操作在我的MainWindow中是一个相当冗长的方法。h/cpp。停止后台 IO activity 的操作大约需要 6 秒,启动大约需要 2 秒。在按下 start/stop 按钮期间,UI 没有响应。本质上,在附加到我的按钮单击事件的插槽中,我需要执行以下逻辑。

void
MainWindow::on_pushButtonStart_clicked(bool checked)
{
    // temporarily disable the pushbutton 
    // until the lengthy operation completes
    mUI->pushButtonStart->setEnabled(false);

    if (checked) {
        // Start the timer tick callback
        mTickTimer.start(APP_TICK, this);
        mUI->pushButtonStart->setText("starting...");

        // This method needs to somehow run in its own QT thread
        // and when finished, call a slot in this MainWindow to
        // re-enable the pushButtonStart and change the statusBar
        // to indicate "runing..."
        performLengthyOperation(true);
        //mUI->pushButtonStart->setText("Stop")
        //mUI->statusBar->setStyleSheet("color: blue");
        //mUI->statusBar->showMessage("runing...");
    } else { // Stop the protocol threads
        // Stop the subsystem protocol tick timer
        mTickTimer.stop();
        mUI->pushButtonStart->setText("stopping...");
        // This method needs to somehow run in its own QT thread
        // and when finished, call a slot in this MainWindow to
        // re-enable the pushButtonStart and change the statusBar
        // to indicate "ready..."
        performLengthyOperation(false);
        // finally toggle the UI controls
        //mUI->pushButtonStart->setText("Start")
        //mUI->statusBar->setStyleSheet("color: blue");
        //mUI->statusBar->showMessage("ready...");
    }
}

当我在寻找有关如何执行此操作的示例时,我遇到了 following article 但我无法将其适应我的场景,因为我需要以某种方式将 MainWindow 放入工作程序以便它可以访问它的 UI 小部件等,这似乎有点矫枉过正。

理想情况下,我正在寻找一种简单的方法来异步 运行 lambda 函数,我可以在其中放置这些耗时的操作(将主窗口作为参数传递)。这比使用 QThreads 和将对象移动到线程等更可取。但我对 QT 框架的了解还不够多,无法知道这样做是否安全或可行。

使用 std::async 和 lambdas:

std::future<void> future; 作为成员添加到您的主窗口 class。

添加插槽 OnLengthyOperationPerformed,代码为:

mUI->pushButtonStart->setText("Stop")
mUI->statusBar->setStyleSheet("color: blue");
mUI->statusBar->showMessage("runing...");
mUI->pushButtonStart->setEnabled(true);

添加信号 void LengthOperationPerformed(); 并将其与 MainWindow 构造函数中的插槽连接。将 Qt::QueuedConnection 作为连接的第五个参数传递,因为您想从主线程调用插槽。

然后在on_pushButtonStart_clicked方法中可以这样写:

future = std::async(std::launch::async, [this] {
  performLengthyOperation(true);
  emit LengthOperationPerformed();
});

与另一个调用相同。只需添加另一个插槽并向插槽发送信号或传递标志即可。

长操作将在另一个线程中 运行,当它完成时 MainWindow 接收信号并重新启用按钮。