2013-04-30 15 views
5
  • Platforma: Qt 4.8.2, Win 7

Proszę rozważyć następujące przepływ logicznych:Prawidłowe wykorzystanie 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 

osiągnąć przepływ używam QProcess aby uruchomić program zewnętrzny dla mnie, aby dołączyć do obrazów, ale pomyliłem się z właściwym wzorcem użycia QProcess. (Nie dbam o komunikatach konsoli ffmpeg, i zależy powodzenie kroku 5, sprawdzając, czy tworzony jest plik wideo.)

Próba 1

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

punkcie (a), Czytałem dokumentację, że to połączenie może zablokować główny interfejs GUI, więc czy powinienem zadzwonić z QThread/QRunnable?

W (b), czy coś tu przeoczyłem? tak jak wtedy, gdy próbuję zamknąć aplikację (krok 7 w przepływie), aplikacja się zawiesza i myślałem, że zrodzony QProcess nie jest poprawnie zwolniony.

Próba 2

napisałem klasy otoki z QProcess następująco:

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

Jak używać Launcher:

void MyWidget::createAVI() 
{ 
    checkAndDeleteAVI(); 
    launcher_.launch("ffmpeg", "argsList"); // launcher_ defined as class member; 
} 

Tak, w punkcie (c), czy nie trzeba czekaćForFinished()? (ponieważ czytałem pewne informacje, że nie powinienem mieszać metody waitForXXX() i signal/slot dla QProcess)

Co więcej, jest coś, co przegapiłem dla klasy Launchera, ponieważ doświadczam również awarii aplikacji podczas korzystania z tego podejścia.

Główne pytanie: Na ogół, kiedy wywołać QProcess :: terminate()/QProcess :: kill() i kiedy usunąć obiekt QProcess?

Dzięki

Odpowiedz

2

Nie trzeba waitForFinished() otrzymasz sygnał o tym, więc na co czekać? Zamiast tego możesz chcieć waitForStarted() w launch(), aby upewnić się, że proces rozpoczął się pomyślnie. Oczywiście w tym przypadku musisz zmienić sposób, w jaki używasz swojego Launcher - nie niszcz go zaraz po launch().

Nie musisz wykonać procesu, jeśli został zakończony, tylko jeśli musisz go przedwcześnie zatrzymać. Możesz go usunąć, gdy otrzymasz finished() lub error() sygnał za pomocą process_->deleteLater() (nie możesz po prostu delete process_, gdy jesteś w gnieździe) lub w swoim ~Launcher(), pod warunkiem, że nie zostanie on wywołany, dopóki proces się nie zakończy.