当MainWindow线程繁忙时,QDialog框显示为空白

问题描述

我正在为基于RaspBerry Pi的机器人开发基于Qt-C ++的前端应用程序。我正在使用Qt 5.9版本以及库QSerialPort和Pigpio。在我的应用程序中,当我将用于命令序列的运行命令提供给机器人时,我的RaspBerry Pi开始与微控制器进行串行通信,并在微控制器中发送一些消息,然后等待接收响应。发送和等待会导致Mainwindow线程冻结。我正在尝试构建紧急停止功能,该功能将在运行过程中停止命令执行。

为此,我尝试将串行通信部分推到单独的线程(QThread)。它没有解决。现在,我试图将紧急停止部件构建到QDialog框中,当我给出运行命令时该对话框会打开,其中包含紧急停止QPushbutton。对话框以非模式形式运行。但是在我当前的代码中,当我给出运行命令时,确实会打开一个对话框,但是对话框完全空白,然后在运行命令结束时关闭(这是有意的)。我将分享一些外观截图。

enter image description here

您能建议我可能要去哪里吗?还是有解决此问题的更好方法?欢迎任何批评和建议!

谢谢!

解决方法

不应阻塞Qt中的主线程。每次调用阻止功能时,GUI和对话框都会冻结。

一种解决方案是使用信号/插槽。它们与Qt融合得很好。但是执行复杂的请求/响应逻辑将需要庞大的状态机,通常容易出错。

有时最好保留此代码的阻塞状态,创建请求/响应代码的纯链,然后将其放入另一个非GUI线程中。然后使用该信号将作业结果通知主线程。

为了停止执行,可以使用原子并在阻塞步骤之间对其进行检查。退出工作功能之前的最大时间延迟是单个阻止功能的最大延迟。您应该仔细调整超时时间。或者,您可以编写自己的函数,该函数可模拟超时和停止条件。它应该检查无限循环中是否有传入数据,并在每次迭代中检查停止条件,该条件必须是超时和停止条件变量。

// pseudocode here
while (true) {
    if (stopCondition) return; // check for emergency condition
    it (currentTime - startTime > timeout) return;
    if (serial->dataReady()) break;
}
auto data = serial->getData();

如果某个步骤可以永远阻止,则无法使用此方法。

有一个QtConcurrent框架示例,该示例演示了QFuture的使用以及函数在单独线程中的工作,而不会阻塞主线程。您可以将所有通信逻辑放入其中。 该代码仅是示例!

#ifndef WORKERCLASS_H
#define WORKERCLASS_H

#include <QObject>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>

class WorkerClass : public QObject
{
    Q_OBJECT
public:
    explicit WorkerClass(QObject *parent = nullptr) : QObject(parent) {
        connect(&futureWatcher,&QFutureWatcher<void>::finished,[this] () {
            emit workFinsihed();
        });
    }

    void startWork(int value) {
        atomic = 0;
        future = QtConcurrent::run(this,&WorkerClass::workFunction,value);
        futureWatcher.setFuture(future);
    }

    void stopWork() {
        atomic = 1;
    }

private:
    QFuture<void> future;
    QFutureWatcher<void> futureWatcher;

    void workFunction(int value) {
        for (int i = 0; i < value; ++i) {
            if (atomic) return;
        }
        return;
    };

    QAtomicInt atomic{0};

signals:
    void workFinsihed();
};

#endif // WORKERCLASS_H