2013-04-30 4 views
5
  • Платформа: Qt 4.8.2, Win 7

Пожалуйста, обратите внимание на следующую логическую схему:Правильное использование QProcess

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) 
} 

В (а), Я прочитал документацию, что этот вызов может заморозить главный графический интерфейс, так что я должен позвонить из QThread/QRunnable?

На (б) я что-то пропустил? как при попытке закрыть приложение (шаг 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), нет необходимости ждатьForFinished()? (поскольку я прочитал некоторую информацию о том, что мне не следует смешивать waitForXXX() и структуру сигнальных/слотов для QProcess)

Кроме того, есть ли что-то, что я пропустил для класса Launcher, так как у меня также наблюдается крушение приложения при использовании этого подхода.

Главный вопрос: В общем случае, когда нужно вызвать QProcess :: terminate()/QProcess :: kill() и когда удалить объект QProcess?

Благодарности

ответ

2

Вам не нужно waitForFinished(), вы будете получать сигнал об этом, так зачем ждать? Вместо этого вы можете захотеть waitForStarted() в launch(), чтобы убедиться, что процесс начат успешно. Конечно, в этом случае вам нужно будет изменить способ использования своего Launcher - не уничтожайте его сразу после launch().

Вам не нужно terminate()/kill() процесс, если он закончен, только если вам нужно преждевременно остановить его. Вы можете удалить его, когда вы получите сообщение finished() или error(), используя process_->deleteLater() (вы не можете просто delete process_, когда находитесь в слоте) или в вашем ~Launcher(), при условии, что он не будет вызываться до завершения процесса.

Смежные вопросы