IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

[QProcess] Récupération de la sortie console


Sujet :

Qt

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut [QProcess] Récupération de la sortie console
    Bonjour,

    dans mon programme, je dois exécuter des applications externes; pour cela j'utilise donc QProcess.
    Ces applications donnent des informations en console sur leur déroulement, qui peut prendre plusieurs minutes. Je voudrais afficher sur mon IHM MainWindow (dans un PlainTextEdit) cette sortie au fur et à mesure du déroulement.

    Pour cela j'ai écrit le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
        QProcess* progExterne = new QProcess();
        progExterne->setWorkingDirectory(projectPath);
        progExterne->start("./progExterne.sh");
        bool processStarted = progExterne->waitForStarted();
        if(!processStarted)
        {
            emit error("Impossible d'executer proExterne.sh.");
            return;
        }
        else
        {
            // Suivi du deroulement de progExterne
            progExterne->waitForReadyRead();
            while(progExterne->state() == QProcess::Running)
            {
                sleep(0.01);
                emit textOut(progExterne->readAllStandardOutput());
            }
        }
    J'ai écrit ce code dans un objet Worker dérivant de QObject (dans une méthode "executer"). Dans ma classe MainWindow, je crée alors un QThread puis utilise la méthode moveToThread pour executer le code de mon objet Worker dans un Thread séparé du Thread principal.
    En effet le contenu de ma méthode executer ne se résume pas au code ci-dessus mais contient d'autres étapes, c'est pourquoi je n'utilise pas directement les QProcess dans la classe MainWindow.

    Mon signal textOut est connecté à un slot de MainWindow, dans lequel j'ajoute le texte reçu en argument dans un QPlainTextEdit.
    ça fonctionne, mais:
    - je ne suis pas certaine de m'y prendre de la bonne manière, cette façon de coder est-elle correcte?
    - l'affichage se passe bien au début mais il est du type:
    "Execution de ProgExterne
    Démarrage...
    Ok
    Execution... 0%"

    Ensuite seul le "0%" bouge en fonction de l'avancement de l'application, sans créer de nouvelle ligne dans la console. Donc l'affichage s'arrête là dans ma MainWindow, le pourcentage ne se met pas à jour... Comment faire?

    Merci d'avance!

  2. #2
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    waitForReadyRead() blocks until new data is available for reading on the current read channel.
    Ce code devrait fonctionner, mais tu peux vérifier que le read channel du processus soit bien celui que tu veux lire QProcess::readChannel(). Selon si ton programme externe écrit sur la sortie standard ou d'erreur, j'imagine que c'est standard et j'imagine aussi que c'est la valeur par défaut de QProcess mais bon.

    Dans tous les cas il me semblerait plus simple et naturel d'utiliser le signal de la sortie standard QProcess::readyReadStandardOutput(), comme pas de question à se poser et pas besoin de faire toi même une boucle d'évènement (tu utilises celles de Qt). En créant simplement un slot qui lit la sortie standard et met à jour ton affichage. Par contre le code devient asynchrone, et tous les traitements que tu fais après l'exécution du processus devraient être déplacés dans un autre slot qui attend la fin du processus (avec le signal QProcess::finished).

    Si ça ne fonctionne toujours pas, essaye de cibler ce qu'il se passe en debug ou avec des traces. Est-ce que le programme externe s'exécute bien et écrit bien sa sortie, est-ce que tu reçois les signaux sur ton QProcess qu'il a bien écrit sa sortie (il pourrait y avoir des buffers à différents endroits qui ne sont pas publiés), est-ce que tu lis bien les bonnes données avant d'essayer de les afficher (ça pourrait être seulement la mise à jour de l'interface qui a un bug et pas la lecture du processus).

  3. #3
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut
    Merci pour la réponse ymoreau, mais je n'y arrive pas...
    J'ai fait ce que tu proposais, un connect() entre le signal readyReadStandardOutput et un slot qui lit la sortie puis l'affiche a l'IHM.
    J'ai aussi connecté le signal finished pour sortir de ma boucle while (dans cette boucle while d'attente du signal finished, il y a uniquement une verification periodique si l'utilisateur a demandé une interruption en cliquant sur un bouton).

    - Quand je lance le QProcess avec start(), aucune sortie ne s'affiche ni dans ma console QtCreator ni dans mon IHM. La boucle while se lance, si j'appuie sur mon bouton "interrompre" cela fonctionne (on sort de la boucle), mais jamais les signaux readyReadStandardOutput et finished ne sont émis (je ne sais même pas si mon process s'est bien lancé puisque aucun affichage).

    - Quand j'utilise startDetached, il se passe exactement la même chose sauf que cette fois je vois le déroulement du programme externe dans la console QtCreator. Mais les deux signaux que j'ai connecté ne sont jamais émis non plus.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    // Reimplementation methode run() de QThread
    MonThread::run()
    {
        demandeInterrupt =false;
        QProcess* progExterne = new QProcess();
        connect(progExterne, SIGNAL(readyReadStandardOutput()), this, SLOT(lireSortie());
        connect(progExterne, SIGNAL(finished(int)), this, SLOT(finProcess(int));
        progExterne->start("./progExterne.sh");
        while(!fini)
        {
            sleep(1);
            if(demandeInterrupt)
                fini = true;
        }
    }
     
    // Appele par le slot d'un bouton "Interrompre" de mon IHM principale
    MonThread::interrompre()
    {
        demandeInterrupt = true;
    }
     
    MonThread::lireSortie()
    {
        qDebug() << "lecture sortie";
        emit textOut(progExterne->readAllStandardOutput());
    }
     
    MonThread::finProcess(int exitCode)
    {
        qDebug() << "fin process";
        fini =true;
    }
    Au final, ce que je veux faire est simple: exécuter deux programmes externes successivement (le premier doit impérativement être terminé avant de lancer le second), tout en affichant la sortie console sur mon IHM. Comment procéderiez-vous? Y a t'il forcément besoin de créer un QThread?

  4. #4
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    Tout d'abord : tu as deux programmes à lancer à la suite, donc pas en parallèle = pas besoin de les mettre chacun dans un thread différent l'un de l'autre. Tu pourrais mettre dans un thread ta procédure qui appelle ces deux programmes si elle est longue et bloquante pour ton interface graphique (sinon l'interface est figée le temps que ta procédure s'exécute). Mais si jamais le plus long est l'appel des programmes externes et pas du traitement que tu fais toi, cette exécution là est déjà faite dans un autre processus donc pas bloquante pour toi sauf si tu bloques toi même ton code avec un while ou un wait.
    En résumé à moins que tu aies des gros traitements en dehors de tes programmes externes tu n'as pas besoin de thread, par contre tu as besoin de synchroniser les processus, ne lancer le second que quand le premier est terminé, pas avec un wait mais en asynchrone. C'est un autre choix que le wait, mais tu es libre de faire ce que tu préfères.

    En résumé l'organisation asynchrone donnerait :
    Etape 1 (une fonction)
    créer process1 et attacher ses signaux sortieStandard pour l'affichage1 et finished pour passer à l'étape 2
    lancer process1
    fin de la fonction, retour à la boucle d'évènements Qt

    Etape 2 (une autre fonction)
    créer process2 et attacher ses signaux sortieStandard pour l'affichage2 et finished pour passer à la fin
    lancer process2
    fin de la fonction

    Etape 3 (encore une autre fonction)
    Faire les traitements que tu veux après que tes deux programmes externes aient terminé


    Ensuite pour trouver pourquoi ça ne marche pas, tu peux peut être mettre un slot sur le signal void QProcess::error(QProcess::ProcessError error) qui affiche une éventuelle erreur du processus, juste pour avoir un log s'il y a un problème. Tu peux aussi faire la même chose sur le signal void QProcess::started() pour vérifier que le process a bien démarré.
    Sinon là comme ça je ne vois pas pourquoi tu ne reçois pas les signaux du QProcess, tu devrais voir passer des erreurs en console si la connexion des slots ne marchait pas.

  5. #5
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut
    En fait je me suis mal exprimée, j'ai bien créé un seul QThread pour mes deux QProcess. Mais je me posais la question si je ne pouvais pas directement créer les QProcess dans mon Thread principal (l'IHM), en me demandant comment faire pour éviter de bloquer l'IHM pendant leur exécution (qui est effectivement longue).
    D'après ta réponse ça à l'air possible, du coup merci je vais tester ça et je reviens faire un retour!

  6. #6
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    J'avais bien compris un seul thread pour les 2 QProcess mais c'était pour détailler les choix possibles, je parlais bien au final d'un seul thread pour ton appli donc comme tu dis le thread principal Qt.
    Et tu avais raison pour ne pas bloquer l'IHM il faut détacher les procédures longues dans un autre thread que celui de l'IHM, c'est simplement que dans ton cas la procédure est déjà détachée dans un autre processus donc ce n'est plus la peine (encore une fois, sauf si tu as aussi des traitements longs dans ton code en plus des QProcess).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. recuperer sortie console d'un QProcess ?
    Par divide dans le forum Qt
    Réponses: 2
    Dernier message: 11/08/2010, 13h52
  2. Date et sortie console énigmatique.
    Par boutade80 dans le forum Langage
    Réponses: 4
    Dernier message: 26/07/2006, 11h34
  3. Réponses: 9
    Dernier message: 21/06/2006, 16h41
  4. Réponses: 7
    Dernier message: 02/09/2005, 15h15
  5. Réponses: 5
    Dernier message: 18/08/2005, 22h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo