Utilisation appropriée de QProcess
- Plate-Forme: Qt 4.8.2, Win 7
Veuillez considérer ce qui suit la logique de flux:
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
Pour atteindre le flux, j'utilise QProcess pour démarrer le programme externe pour moi de rejoindre les images, mais j'ai confondu avec le bon mode d'utilisation de QProcess. (Je ne me préoccupe pas de messages dans la console de ffmpeg, je déterminer le succès de l'étape 5 par vérifier si le fichier vidéo est créé.)
Tentative 1
void MyWidget::createAVI()
{
checkAndDeleteAVI();
process = new QProcess(this); //process_ defined as class member;
process->start("ffmpeg -f images2 ....");
process->waitForFinished(-1); //(a)
//(b)
}
À (un), j'ai lu la documentation le présent appel peut geler l'interface graphique principale, donc dois-je appeler à partir de QThread/QRunnable?
À (b), suis-je raté quelque chose ici? comme lorsque je tente de fermer l'application (étape 7 du flux), l'application se bloque, et je pensais que les engendré QProcess n'est pas correctement publiés.
Tentative 2
J'ai écrit une classe wrapper de QProcess:
Lanceur.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;
}
Comment j'utilise le Launcher:
void MyWidget::createAVI()
{
checkAndDeleteAVI();
launcher_.launch("ffmpeg", "argsList"); //launcher_ defined as class member;
}
Ainsi, en (c), qu'il est inutile de waitForFinished()? (comme je l'ai lu quelques infos que je ne devrais pas mélanger waitForXXX() et signal/slot cadre de QProcess)
Aussi, il ya quelque chose que j'ai raté pour le Lanceur de classe, comme je l'ai aussi l'expérience de l'application crash lors de l'utilisation de cette approche.
question Principale: En général, quand appeler QProcess::terminate() /QProcess::kill(), et quand à supprimer le QProcess objet?
Grâce
OriginalL'auteur YamHon.CHAN | 2013-04-30
Vous devez vous connecter pour publier un commentaire.
Vous n'avez pas besoin de
waitForFinished()
, vous allez recevoir le signal à ce sujet, alors pourquoi attendre? Au lieu de cela, vous pourriezwaitForStarted()
danslaunch()
pour être sûr que le processus a démarré avec succès. Bien sûr, dans ce cas, vous aurez besoin de changer la façon dont vous utilisez votreLauncher
- ne pas détruire juste aprèslaunch()
.Vous n'avez pas besoin de
terminate()
/kill()
le processus si elle a fini, si vous avez besoin d'arrêter prématurément. Vous pouvez le supprimer lorsque vous recevezfinished()
ouerror()
signal à l'aide d'process_->deleteLater()
(vous ne pouvez pas simplementdelete process_
pendant que vous êtes dans la fente) ou dans votre~Launcher()
, pourvu qu'il ne sera pas appelé jusqu'à ce que le processus est terminé.OriginalL'auteur Paul