QProcess的正确用法

5
  • 平台: 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步是否成功。)
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个回答

2

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接