如何避免使用 QProcess 的 waitForStarted 来阻止 GUI 冻结?

How to avoid waitForStarted with QProcess to stop GUI from freezing?

我正在 运行使用 QProcess 将 wscript 转换为 运行 一个 VB 脚本,该脚本将 Excel 文件转换为制表符分隔的文本文件。脚本 运行 一切正常,但 GUI 冻结并且用户在很长一段时间内无法与其交互。这是代码:

/* Create txt files and store paths */
for (int i = 0; i < excelFilepaths.size(); ++i) {    
    wscript->start("wscript.exe", QStringList() << vbs.fileName() << excelFilepaths.at(i) << newDir.absolutePath() + "/" + QString::number(i + 1));
    wscript->waitForFinished();
    payloadPaths.push_back(newDir.absolutePath() + "/" + QString::number(i + 1));
}

所以发生的事情是我有多个 excel 文件路径和一个分配在堆上的 QProcess。此 QProcess 运行s VB 脚本将 excel 文件转换为文本文件,然后存储新文本文件的路径。这需要很长时间(4 excel 个文件大约需要 20 秒)。在此期间,GUI 被冻结。我希望用户能够使用不干扰进程的 GUI 部分。

现在我怀疑这个问题的原因是

QProcess::waitForFinished()

而且我已经在线阅读了有关连接 QProcess 的 finished() 和 error() 信号以消除此问题的信息。但是我一直很难这样做。我将此代码 运行 设置为 class 的方法,它继承自 QObject 并包含 Q_OBJECT 宏,因此应设置所有内容。我只需要一些帮助来将其余部分放在一起。我怎样才能使我的 GUI 在 QProcess 运行ning 时不冻结?请帮忙

我遇到了同样的问题,但是 QSerialPort。但是,我认为解决方案是相同的。我找不到让 "serial->waitForReadyRead()" 不冻结 GUI 的方法,所以,我实现了自己的功能。

void Research::WaitSerial(int MilliSecondsToWait)
{
    QTime DieTime = QTime::currentTime().addMSecs(MilliSecondsToWait);
    flag = 0;
    while(QTime::currentTime() < DieTime && !flag)
    {
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
        if(BufferSerial != "")
        {
            flag++;
        }
    }
}

当然,你的问题类似但不相同。只需将 if 更改为您的 "stopping condition"。希望这有帮助。


编辑:这不是我最初的想法。我在某处的论坛上找到了它。所以我不收学分。

在名为 Synchronous Process API 的部分引用文档:

  • waitForStarted() blocks until the process has started.
  • waitForReadyRead() blocks until new data is available for reading on the current read channel.
  • waitForBytesWritten() blocks until one payload of data has been written to the process.
  • waitForFinished() blocks until the process has finished.

Calling these functions from the main thread (the thread that calls QApplication::exec()) may cause your user interface to freeze.

记住这一点。但是,您可以使用 that:

之类的方法来解决此问题
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus){ /* ... */ });

请注意,还有一些 signals 可能适合任何所需的目的。