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

PyQt Python Discussion :

Écrire stdout dans un QTextEdit en "temps réel"


Sujet :

PyQt Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 26
    Points : 20
    Points
    20
    Par défaut Écrire stdout dans un QTextEdit en "temps réel"
    Bonjour à tous,

    (Pyqt 4.5.1 - Linux - python 2.6.2)

    J'ai une interface graphique qui, lors de l'appui sur un bouton, lance un script qui écrit ce qu'il fait sur la sortie standard stdout. Je souhaiterais afficher non pas sur stdout mais dans un widget qtextedit (en mode readonly) en "temps réel" c'est à dire de façon similaire à la façon dont les logs s'affichent sur stdout.

    Après de nombreuses recherches, je n'arrive toujours pas à mes fins ... Les logs de mon script s'écrivent en deux gros paquets.

    Voici le principe que j'ai utilisé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    (...)
    QtCore.QObject.connect(self.processLog,QtCore.SIGNAL("readyReadStandardOutput()"), self.log)
     
    (...)
     
    Def log():
    (...)
         While canReadLine():
             Self.textEdit.append(self.proc.readLine())
    (...)

    Mais les logs s'affichent dans le qtextedit en deux fois vers le milieu de l'exécution et vers la fin et à chaque fois en envoyant la moitié des logs d'un coup.
    La fonction readyreadstandardoutput ne devrait elle pas envoyer un signal dès qu'une nouvelle ligne est apparue dans stdout et donc le qtext widget se remplir en "temps réel"?

    Merci de votre aide !

  2. #2
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 751
    Points
    1 751
    Par défaut
    Peux-tu nous mettre un ECM (Exemple Complet Minimal) ?

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 26
    Points : 20
    Points
    20
    Par défaut
    Bien sûr,

    j'ai même trouvé une piste mais pas d'explication valable !

    Pour résumer, j'ai une UI en pyqt qui appelle lorsqu'on clique sur un bouton un programme en python qui affiche des infos sur la sortie standard. Mon but est de ne pas écrire ces infos sur la sortie standard mais dans un QTextEdit en readonly de mon UI.

    Le problème est que les données ne s'affichent pas en temps réel mais par bloc (bufferisation?) dans le QTextEdit alors que si je lance le programme python en ligne de commande, tout s'écrit en temps réel sur la sortie standard .

    Si par contre je fais la même chose mais que j'appelle un programme en ksh et non en python, tout s'écrit en temps réel sur la sortie standard ou dans le QTextEdit...

    j'ai codé un exemple mettant en évidence le problème (commenter décommenter le type de script lancé pour passer de python à ksh) :

    l'Interface Graphique :

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    from PyQt4 import QtCore, QtGui
    import commands, os
     
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(400, 400)
            self.centralwidget = QtGui.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.textEdit = QtGui.QTextEdit(self.centralwidget)
            self.textEdit.setGeometry(QtCore.QRect(50, 20, 300, 200))
            self.textEdit.setReadOnly(True)
            self.textEdit.setObjectName("textEdit")
            self.pushButton = QtGui.QPushButton(self.centralwidget)
            self.pushButton.setGeometry(QtCore.QRect(160, 260, 75, 23))
            self.pushButton.setObjectName("pushButton")
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtGui.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 400, 22))
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtGui.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
     
            self.processLog = QtCore.QProcess()
     
            self.retranslateUi(MainWindow)
            QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), self.launchScript)
            QtCore.QObject.connect(self.processLog,QtCore.SIGNAL("readyReadStandardOutput()"), self.log)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
     
        def retranslateUi(self, MainWindow):
            MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
     
        def launchScript(self):
            self.processLog.start("script.ksh")
            #self.processLog.start("python script.py")
     
        def log(self):
            while self.processLog.canReadLine():
                self.textEdit.append(str(self.processLog.readLine()))
     
     
    if __name__ == "__main__":
        import sys
        app = QtGui.QApplication(sys.argv)
        MainWindow = QtGui.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    Le programme appelé en python :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for i in range (1,10000):   
        print i
        for j in range (1,10000):
            toto = 1
    Le programme appelé en ksh :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/ksh
     
    for i in `seq 1 10000`
    do
        echo $i
        for i in `seq 1 10000`
        do
    	TOTO=1
        done
    done

  4. #4
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 751
    Points
    1 751
    Par défaut
    C'est étrange... A chaque fois que j'ai vu des appels de scripts, je tombais toujours sur une seule sortie en un seul bloc. Donc le souci doit venir de là. Maintenant ceci ne va pas dire qu'il n'y a pas de solution.

    J'ai essayé par exemple 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
    #!/usr/bin/env python
    #coding=utf-8
    import os
     
    import subprocess
    fileToTest = "cheminDuFichier"
     
    os.chdir(os.path.dirname(fileToTest))
    x = subprocess.Popen(["python.exe", fileToTest], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    #                    print "code retour:",x.wait()
    #                    print "sortie standard"
    print x.stdout.read()
    Et tout sort d'un seul coup. Je ne sais pas quoi te dire. Il faudrait regarder la doc. un peu plus en profondeur. Cela est faisable car j'utilise Ulipad qui a été développé en Python.
    J'ai ouvet un nouveau post sur le sujet car cela m'intrigue...

    Sinon essayes de poser ta question aux grands manitoux de la liste PyQt. Je sais c'est nul comme réponse...

    PS : pour le script Python de test, tu peux le faire comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #!/usr/bin/env python
    #coding=utf-8
    import time
    for i in range (1,5):   
        print i
        time.sleep(3)

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 26
    Points : 20
    Points
    20
    Par défaut
    Merci de la rapidité de réponse !

    Juste pour information, le fait d'utiliser mon script python permet de mettre en évidence le fait que tout ne sort pas à la fin mais lorsqu'un certain nombre de données sont écrites OU à la fin si pas assez de données ont été écrites (ton cas).

    Mais dans mon cas on obtient des logs qui apparaissent par bloc, c'est pour ça que je pensais à une bufferisation mais où ?

    edit : en lançant ton programme qui appelle mon script, tout apparaît à la fin. En lançant mon programme appelant mon script, tout apparaît par gors bloc de logs ...

    bon je laisse passer le week end je m'y pencherai plus tard ou trouverai une solution de contournement grr

  6. #6
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 751
    Points
    1 751
    Par défaut
    Va sur la liste PyQt, je pense que tu auras une réponse rapide. Je peux leur envoyer un mail si tu veux.

  7. #7
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 751
    Points
    1 751
    Par défaut
    Salut, j'avais la solution sous les yeux depuis un moment. Je travaille avec UliPad dont la console commence par quelque chose du type:
    "C:\Python26\python.exe" -u "C:\Documents and Settings\...\Console.py"

    Du coup j'ai essayé dans ton code de mettre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.processLog.start('python.exe -u script.py')
    Problème résolu.

    Cela me fait penser à ce proverbe : "Quand le sage montre la lune, le singe regarde le doigt." Pour le coup je me sens un peu singe...

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 26
    Points : 20
    Points
    20
    Par défaut
    Tout marche merci beaucoup,

    J'aurais pu y penser car j'étais sur la piste avec mon idée de bufferisation !! grr

    Avant de clore le sujet, l'explication détaillée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Manpage de Python :
    
    Options de la ligne de commande :
    
    [...]
    
    -u  Force les flux stdin, stdout et stderr à être sans tampon.
    
    [...]

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 16/06/2006, 03h29
  2. [VB.NET]comment écrire/lire dans un fichier text
    Par zouhib dans le forum Windows Forms
    Réponses: 1
    Dernier message: 19/05/2006, 17h11
  3. [UDP] temps-réel dans un jeu - stratégie à adopter ?
    Par docteur_re dans le forum Développement
    Réponses: 5
    Dernier message: 10/04/2006, 11h40
  4. insertion d'un objet 3D dans une video en temps réel
    Par chabfive dans le forum OpenGL
    Réponses: 5
    Dernier message: 02/11/2005, 13h10

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