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 :

QThread et pyqtgraph


Sujet :

PyQt Python

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur développement de composants
    Inscrit en
    Décembre 2019
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement de composants

    Informations forums :
    Inscription : Décembre 2019
    Messages : 113
    Par défaut QThread et pyqtgraph
    Bonjour,
    j'utilise pyqtgraph et QTthread pour faire des graphiques "live".
    je joue un peu avec ces deux là et ça fonctionne bien...

    je me pose une question d'architecture (je crois que c'est comme ça que ça s'appelle).
    il vaut mieux:

    - instancier des variables dans un QMainWindow et les appeler depuis le run de la classe QThread pour les mettre à jour (typiquement les listes des datas x et y)?
    - instancier les variables dans le QThread et les retourner (si besoin) à QMainWindows?

    pour l'instant je préfère la première possibilité... mais est-ce le mieux? dans la seconde possibilité j'ai l'impression que "l'avantage" c'est de tout gérer dans le Qthread...
    mais en même temps, le fait d'avoir les variables dans QMainWindow me semble plus "sécuritaire" en cas d'arrêt/plantage du Qthread.

    c'est quoi le mieux?
    merci

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour

    Je préfère pour ma part une 3ème solution. Dans la mesure où l'exécution du thread est asynchrone par rapport au programme:
    - le thread envoie des signaux au programme quand il a des données à lui communiquer
    - ces signaux sont récupérés par des méthodes du QMainWindows, qui saura en utiliser les données au bon moment.

    Pour des infos sur les signaux: https://www.riverbankcomputing.com/s...als_slots.html

    C'est comme ça, par exemple, qu'on fait fonctionner une barre de progression graphique pour une opération longue (calcul, téléchargement, ...). Rappelons que le thread ne doit pas toucher directement aux éléments graphiques pour les mettre à jour (plantage aléatoire). La communication par signaux est ce qu'il y a de plus approprié avec la conception de la bibliothèque graphique.

    Il reste, bien sûr, possible d'avoir des données "partagées" entre le thread et le programme principal, à condition d'empêcher les "collisions" (tentative d'accès simultanées) avec des verrous.

    Voilà un petit exemple d'utilisation des signaux (PyQt5):

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    # -*- coding: utf-8 -*-
     
    import sys
    import time
    from PyQt5 import (QtWidgets, QtCore)
     
    #############################################################################
    class Operationlongue(QtCore.QThread):
     
        # création des nouveaux signaux
        info = QtCore.pyqtSignal(int) # signal pour informer d'une progression
        fini = QtCore.pyqtSignal(bool, list) # signal pour la fin du thread
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.stop = False # drapeau pour exécuter une demande d'arrêt
     
        #========================================================================
        def run(self):
            """partie qui s'exécute en tâche de fond
            """
            for i in range(0, 101):
                if self.stop:
                    break # arrêt anticipé demandé
                time.sleep(0.05)
                self.info.emit(i) # envoi du signal de progression d'exécution
            # fin du thread
            self.fini.emit(self.stop, [1,2,3]) # envoi du signal de fin d'exécution
     
        #========================================================================
        def arreter(self):
            """pour arrêter avant la fin normale d'exécution du thread
            """
            self.stop = True
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            # bouton de lancement du thread
            self.depart = QtWidgets.QPushButton("Départ", self)
            self.depart.clicked.connect(self.lancement)
     
            # bouton d'arrêt anticipé du thread
            self.arret = QtWidgets.QPushButton(u"Arrêt", self)
            self.arret.clicked.connect(self.arreter)
     
            # barre de progression
            self.barre = QtWidgets.QProgressBar(self)
            self.barre.setRange(0, 100)
            self.barre.setValue(0)
     
            # positionne les widgets dans la fenêtre
            posit = QtWidgets.QGridLayout()
            posit.addWidget(self.depart, 0, 0)
            posit.addWidget(self.arret, 1, 0)
            posit.addWidget(self.barre, 2, 0)
            self.setLayout(posit)
     
            # initialisation variable d'instance de classe
            self.operationlongue = None
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def lancement(self, ok=False):
            """lancement de l'opération longue dans le thread
            """
            if self.operationlongue==None or not self.operationlongue.isRunning():
                # initialise la barre de progression
                self.barre.reset()
                self.barre.setRange(0, 100)
                self.barre.setValue(0)
                # initialise l'opération longue dans le thread
                self.operationlongue = Operationlongue()
                # prépare la réception du signal de progression
                self.operationlongue.info.connect(self.progression)
                # prépare la réception du signal de fin
                self.operationlongue.fini.connect(self.stop)
                # lance le thread (mais ne l'attend pas avec .join!!!)
                self.operationlongue.start()
     
        #========================================================================
        @QtCore.pyqtSlot(int)
        def progression(self, i):
            """lancé à chaque réception d'info de progression émis par le thread
            """
            self.barre.setValue(i)
            QtCore.QCoreApplication.processEvents() # force le rafraichissement
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def arreter(self, ok=False):
            """pour arrêter avant la fin
            """
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.arreter()
     
        #========================================================================
        @QtCore.pyqtSlot(bool, list)
        def stop(self, fin_anormale=False, liste=()):
            """Lancé quand le thread se termine
            """
            if fin_anormale:
                # fin anticipée demandée
                QtWidgets.QMessageBox.information(self,
                    "Opération longue",
                    "Arrêt demandé avant la fin!")
            else:
                # fin normale
                self.barre.setValue(100)
                QtWidgets.QMessageBox.information(self,
                    "Opération longue",
                    "Fin normale!")
                # récupération des infos transmises par signal à la fin du thread
                print(liste)
     
        #======================================================================== 
        def closeEvent(self, event):
            """lancé à la fermeture de la fenêtre quelqu'en soit la méthode
            """
            # si le thread est en cours d'eécution, on l'arrête (brutalement!)
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.terminate()
            # et on accepte la fermeture de la fenêtre dans tous les cas
            event.accept()
     
    ############################################################################# 
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 695
    Par défaut
    Salut,

    On instancie les objets d'une classe et on y accède via variables/attributs. Et tous les objets ne pourront pas être partagés entre threads sans précaution (si on veut que les modifications restent cohérentes...)

    Citation Envoyé par clement_74
    je me pose une question d'architecture (je crois que c'est comme ça que ça s'appelle).
    il vaut mieux:
    Qt propose sa propre architecture basée sur signaux/slots (en plus des mécanismes de base).... Toute la difficulté est d'apprendre à faire avec la boîte à outils que propose Qt (ce qu'on fera autrement avec une autre boîte à outils).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [QThread] QProcess et QSemaphore
    Par slymira dans le forum Multithreading
    Réponses: 11
    Dernier message: 29/11/2007, 11h40
  2. [QThread] QThread qui fait figger le programme
    Par alpha_one_x86 dans le forum Multithreading
    Réponses: 1
    Dernier message: 29/11/2007, 10h16
  3. [QThread] ne marche pas
    Par alpha_one_x86 dans le forum Multithreading
    Réponses: 11
    Dernier message: 23/11/2007, 09h13
  4. [Thread] QThread et QSocket
    Par G3G3 dans le forum Multithreading
    Réponses: 7
    Dernier message: 30/10/2007, 20h25

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