正确使用 QProcess

Posted

技术标签:

【中文标题】正确使用 QProcess【英文标题】:Proper usage of QProcess 【发布时间】:2013-04-30 09:51:49 【问题描述】: 平台:Qt 4.8.2,Win 7

请考虑以下逻辑流程:

1. App started
2. functionA() triggered
3. the app periodically capture some images to external files
4. end of functionA()
5. the app create a video from captured images, using ffmpeg as external program
6. [step 2 -> step 5] may be repeated.
7. App quit

为了实现流程,我使用 QProcess 启动外部程序让我加入图像,但我对 QProcess 的正确使用模式感到困惑。 (我不关心ffmpeg的控制台消息,我通过检查是否创建了视频文件来确定步骤5的成功。)

尝试 1

void MyWidget::createAVI()

    checkAndDeleteAVI();
    process = new QProcess(this); // process_ defined as class member;
    process->start("ffmpeg -f images2 ....");
    process->waitForFinished(-1);  // (a)
    // (b)

在 (a) 处,我阅读了该调用可以冻结主 GUI 的文档,所以我应该从 QThread/QRunnable 调用吗?

在 (b) 处,我错过了什么吗?当我尝试关闭应用程序时(流程中的第 7 步),应用程序崩溃了,我认为生成的 QProcess 没有正确释放。

尝试 2

我写了一个 QProcess 的包装类如下:

Launcher.h

class Launcher : public QObject

    Q_OBJECT
public:
    /** constructor */
    explicit Launcher(QObject *parent = 0);
    /** destructor */
    ~Launcher() 
        if (started_ && process_->state() != QProcess::NotRunning)
            process_->kill();
     // end_dtor(Launcher)
Q_SIGNALS:
    void feedbackLog(QString log);
public Q_SLOTS:
    void launch(QString program, QStringList argList);
private:
    QProcess * process_;
    bool started_;
private Q_SLOTS:
    void error(QProcess::ProcessError error);
    void finished(int exitCode, QProcess::ExitStatus status);
    void stateChanged(QProcess::ProcessState state);
; // end_class(Launcher)

#endif // LAUNCHER_H

Launcher.cpp

#include "launcher.h"
#include <QCoreApplication>
#include <QtDebug>

Launcher::Launcher(QObject *parent) : QObject(parent), started_(false)

    process_ = new QProcess(this);
    connect(process_,
            SIGNAL(error(QProcess::ProcessError)),
            SLOT(error(QProcess::ProcessError)));
    connect(process_,
            SIGNAL(finished(int, QProcess::ExitStatus)),
            SLOT(finished(int, QProcess::ExitStatus)));
    connect(process_,
            SIGNAL(stateChanged(QProcess::ProcessState)),
            SLOT(stateChanged(QProcess::ProcessState)));
 // end_ctor(ExternalLauncher)

void Launcher::launch(QString program, QStringList argList)

    started_ = true;
    process_->start(program, argList);
    process_->waitForFinished(-1); // (c)
    Q_EMIT feedbackLog(process_->readAllStandardOutput());
    process_->close();
 // end Launcher::launch()

void Launcher::error(QProcess::ProcessError error)

    /* just feedback some text about the error */
 // end_slot(Launcher::error)

void Launcher::finished(int exitCode, QProcess::ExitStatus status)

    started_ = false;
    /* feedback some text about finished */
 // end_slot (Launcher::finished)

void Launcher::stateChanged(QProcess::ProcessState state)

    qDebug() << "Luancher::stateChanged" << state;

我如何使用启动器:

void MyWidget::createAVI()

    checkAndDeleteAVI();
    launcher_.launch("ffmpeg", "argsList"); // launcher_ defined as class member;

那么,在 (c) 处,是否不需要 waitForFinished()? (当我读到一些信息时,我不应该混淆 waitForXXX() 和 QProcess 的信号/槽框架)

另外,Launcher 类有什么我错过的,因为我在使用这种方法时也遇到了应用程序崩溃。

主要问题:一般来说,什么时候调用QProcess::terminate()/QProcess::kill(),什么时候删除QProcess对象?

谢谢

【问题讨论】:

【参考方案1】:

你不需要waitForFinished(),你会收到关于它的信号,所以为什么要等呢?相反,您可能希望在launch() 中输入waitForStarted() 以确保进程已成功启动。当然,在这种情况下,您需要更改使用 Launcher 的方式 - 不要在 launch() 之后立即销毁它。

如果进程已经完成,你不需要terminate()/kill(),只有当你需要提前停止它时。当你收到finished()error() 信号时,你可以删除它,使用process_-&gt;deleteLater()(你不能只在插槽中时delete process_)或~Launcher(),前提是它不会被调用直到过程完成。

【讨论】:

以上是关于正确使用 QProcess的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用 Composer 安装 Laravel 扩展包

如何正确使用 Composer 安装 Laravel 扩展包

如何正确使用 Composer 安装 Laravel 扩展包

如何正确强制正确使用类方法?

如何正确使用 Composer 安装 Laravel 扩展包

C#注释的正确的使用方法有哪些?