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 :

Comment ne pas bloquer la GUI pendant le travail ?


Sujet :

PyQt Python

  1. #1
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut Comment ne pas bloquer la GUI pendant le travail ?
    Bonsoir,

    je voudrais lancer des commandes python et autre (os.system, subprocess...) sans bloquer l'interface graphique.

    Je m'explique, une fois le travail en cours, impossible de cliquer ou que ce soit.

    En bash je lançais ces commandes en fond via &.

    Comment peut-on faire en python ?

    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
    cmd = ["mkvextract", "tracks", "/home/hizoka/Fichier.mkv", '0:"/home/hizoka/0_Video.mkv"', '1:"/home/hizoka/1_Audio_dts_eng.dts"']
     
    try:
        reply = subprocess.Popen(cmd, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    except (IOError, OSError) as exc:
        self.print_(u"\nSubprocess ERROR: {0}".format(exc))
        return
     
    old_text = ""
    while 1:
        text = reply.stdout.readline()[:-1]
        if type(text) != str or text == '' and reply.poll() != None: # Terminé !
            break
        elif old_text == text:
            pass
        else:
            old_text = text
            if "Progression" in text:
                chains = text.split(":")
                try:
                    value = int(chains[1].strip().replace('%', ''))
                except:
                    pass
                else:
                    self.ui.progressBar.setValue(value)
    Dans le cas présent, l'avancement va bien fonctionner mais impossible de cliquer tant que ce n'est pas fini car cela occupe le script.
    Il faudrait pouvoir lancer cette boucle infinie en fond...

    Autre exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def MKValidator(self):
        self.ui.progressBar.setMaximum(0) # Permet de faire progresser automatiquement la progressbar
        os.system('mkclean "{}"'.format(Configs["MKVLink"]))
        self.ui.progressBar.setMaximum(100) # Arrête la progression auto
    Il ne se passe rien dans le cas présent, pas de progression dans la progressbar...
    j'ai testé également avec subprocess.Popen, subprocess.check_out.
    La, le soucis est le meme, si je surveille la commande pour savoir quand arreter la progression automatique, je bloque mon logiciel.

    Une idée de comment surveiller ces commandes pour envoyer la progression ou non sans bloquer la gui (qui permettrait le clic sur un bouton pour stopper le travail) ?

    Voilou

    Merci.
    Sous Kubuntu 20.04

  2. #2
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2013
    Messages : 89
    Points : 91
    Points
    91
    Par défaut


    Je précise d'abord que je suis loin d'être un expert en python, il y a plus de chance que ce soit faux que vrai. mais je :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     self.print_(u"\nSubprocess ERROR: {0}".format(exc))
    Ne mettrais pas de u puisque tu codes en Python 3.3.Par contre si c'était en 2.7.x ce serait le cas.

    Ferais comme ça (à la fin):

    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
    cmd = ["mkvextract", "tracks", "/home/hizoka/Multimedia/Videos/Films/HD/World War Z.mkv", '0:"/home/hizoka/Download/0_Video_World.War.Z.2013.MULTi.UNRATED.1080p.BluRay.x264.AC3.DTS-SALEM.mkv"', '1:"/home/hizoka/Download/1_Audio_dts_eng.dts"']
     
    try:
        reply = subprocess.Popen(cmd, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    except (IOError, OSError) as exc:
        self.print_(u"\nSubprocess ERROR: {0}".format(exc))
        return
     
    old_text = ""
    while 1:
        text = reply.stdout.readline()[:-1]
        if type(text) != str or text == '' and reply.poll() != None: # Terminé !
            break
        elif old_text == text:
            pass
        else:
            old_text = text
            if "Progression" in text:
                chains = text.split(":")
                try:
                    value = int(chains[1].strip().replace('%', ''))
                    self.ui.progressBar.setValue(value)
                except:
                    pass
    Et je rajouterai un break pour casser la boucle While. Cela peut expliquer pourquoi cela ne s'arrete pas.

  3. #3
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2013
    Messages : 89
    Points : 91
    Points
    91
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ef MKValidator(self):
        self.ui.progressBar.setMaximum(0) # Permet de faire progresser automatiquement la progressbar
        os.system('mkclean "{}"'.format(Configs["MKVLink"]))
        self.ui.progressBar.setMaximum(100) # Arrête la progression auto
    Une erreur dans ton code cad tu mets
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.ui.progressBar.setMaximum(0) # Permet de faire progresser automatiquement la progressbar
    Ne serait-ce pas plutot setMinimum(0)

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par hizoka Voir le message
    En bash je lançais ces commandes en fond via &.
    Ca fonctionnait parce que le GUI (GTK-server) était aussi dans un thread sépare.

    Comment peut-on faire en python ?
    Par défaut, Python est un langage de scripting mais le GUI démarre dans le thread principal comme avec n'importe quel autre langage de programmation "normal". Si vous faites autre chose, le GUI se gèle.

    Si vous ne voulez pas trop cassez la logique, ça serait pas mal de pousser le GUI dans un thread a lui et garder la main sur le thread principal. Comme ce n'est pas le "standard", ce sera peut être "plus complique", voir ici par exemple.

    Avec le mode de fonctionnement "normal" (GUI dans thread principal), il faut revoir toutes les interfaces et la logique qui va avec.

    Ceci dit, comme c'est quand même "basique". Il y a plein d'exemples qui traînent dans ce forum ou qui sont accessibles via google ou autre.

    A vous de voir ce qui est le moins pire cote changements.

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

  5. #5
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonsoir,

    Pour lancer une opération longue à partir d'un GUI sans le bloquer, j'utilise d'habitude un thread (QThread). Le principe est le suivant:

    - le GUI lance le thread, mais rend tout de suite la main au GUI. Ainsi, à notre échelle au moins, le GUI et le thread semblent s'exécuter en même temps ( le GUI n'est pas bloqué).

    - mais le thread ne peut pas toucher directement aux éléments graphiques! Si on veut que le thread renseigne le GUI pendant son exécution, par exemple d'un avancement, il lui envoie un message avec emit.

    - à la fin de son exécution, le thread peut aussi envoyer un message pour signaler sa fin.

    Dans les 2 cas, le message peut encapsuler des données.

    Dans les 2 cas, on crée des signaux spécifiques.

    - Du côté du GUI, la réception des messages d'avancement et de la fin du thread est préparée avec connect. Donc, à chaque réception d'un message, la méthode prévue s'exécute pour agir sur le graphique par exemple..

    Si tu veux un exemple, je peux t'en monter un.

    Mais avec un processus, je ne sais pas si on peut faire la même chose.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  6. #6
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    tyrtamos => Ta solution me parait être la meilleure et j'arrive à en comprendre le principe mais je vais avoir besoin d'un bon exemple
    Sous Kubuntu 20.04

  7. #7
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Voilà un petit exemple:

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    # Python 2.7
     
    import sys, os, time
     
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Operationlongue(QtCore.QThread):
     
        # création des nouveaux signaux
        info = QtCore.pyqtSignal(int)
        fini = QtCore.pyqtSignal()
     
        #========================================================================
        def __init__(self, parent=None):
            super(Operationlongue, self).__init__(parent)
     
        #========================================================================
        def run(self):
            """partie qui s'exécute en tâche de fond"""
            for i in range(0, 101):
                time.sleep(0.05)
                self.info.emit(i)
            # fin du thread
            self.fini.emit()
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super(Fenetre,self).__init__(parent)
     
            self.depart = QtGui.QPushButton(u"Départ", self)
            self.depart.clicked.connect(self.lancement)
     
            self.barre = QtGui.QProgressBar(self)
            self.barre.setRange(0, 100)
     
            self.barre.setValue(0)
     
            posit = QtGui.QGridLayout()
            posit.addWidget(self.depart, 0, 0)
            posit.addWidget(self.barre, 1, 0)
            self.setLayout(posit)        
     
            self.operationlongue = None
     
        #========================================================================
        def lancement(self, ok):
     
            if self.operationlongue==None or not self.operationlongue.isRunning():
                # initialisation de la barre de progression
                self.barre.reset()
                self.barre.setRange(0, 100)
                self.barre.setValue(0)
                # démarre l'opération longue dans le thread
                self.operationlongue = Operationlongue()
                self.operationlongue.info.connect(self.progression)
                self.operationlongue.fini.connect(self.stop)
                self.operationlongue.start()
     
        #========================================================================
        @QtCore.pyqtSlot(int)
        def progression(self, i):
            """lancé à chaque réception d'info émis par le thread"""
            self.barre.setValue(i)
            QtCore.QCoreApplication.processEvents() # force le rafraichissement
     
        #========================================================================
        @QtCore.pyqtSlot()
        def stop(self):
            """Lancé quand le thread se termine"""
            self.barre.setValue(100)
            QtGui.QMessageBox.information(self,
                u"Téléchargement",
                u"Opération terminée!")
     
        #========================================================================
        def closeEvent(self, event):
            """lancé à la fermeture de la fenêtre quelqu'en soit la méthode"""
            if self.operationlongue.isRunning():
                self.operationlongue.terminate()
            event.accept()
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  8. #8
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    Bien qu'un peu complexe j'ai plutot bien compris ton exemple

    et dans le cas ou l'on voudrait un bouton annulant ce qui se passe sur quoi faudrait-il agir ?
    Sur les connexions ? en envoyant le signal de fin ou un autre signal ?
    en ajoutant une vérification (de la présence d'un fichier ou d'une variable par ex) dans le run de Operationlongue ?

    @ Cenwen
    => pour le u"" en effet ce n'est pas necessaire mais j'ai copié collé la proposition de vins vite fait, je ne l'utilise pas encore.

    => Normalement apres tous mes tests, la boucle s'arrete nickel a chaque fois.

    => Et c'est min setMinimum qu'il faut mettre à 0 (teste sur qtdesigner tu verras le resultat directement )


    @ wiztricks
    Merci pour le lien je regarderai ca plus en detail demain
    Sous Kubuntu 20.04

  9. #9
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Pour arrêter un QThread, on a en gros 2 solutions:

    1- la tâche dans la méthode run s'exécute dans une boucle: on met un drapeau qui déclenchera sur demande l'arrêt anticipé.

    Voilà le code précédent complété qui fait ça. Comme le thread doit tout de même signaler au GUI que son arrêt est anormal, le signal de fin porte le drapeau en question (self.stop=False pour une fin normale, True pour une fin anticipée). Mais on aurait pu créer un nouveau signal pour ça.

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    # Python 2.7
     
    import sys, os, time
     
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Operationlongue(QtCore.QThread):
     
        # création des nouveaux signaux
        info = QtCore.pyqtSignal(int)
        fini = QtCore.pyqtSignal(bool)
     
        #========================================================================
        def __init__(self, parent=None):
            super(Operationlongue, self).__init__(parent)
     
            self.stop = False
     
        #========================================================================
        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)
            # fin du thread
            self.fini.emit(self.stop)
     
        #========================================================================
        def arreter(self):
            """pour arrêter avant la fin normale"""
            self.stop = True
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super(Fenetre,self).__init__(parent)
     
            self.depart = QtGui.QPushButton(u"Départ", self)
            self.depart.clicked.connect(self.lancement)
     
            self.arret = QtGui.QPushButton(u"Arrêt", self)
            self.arret.clicked.connect(self.arreter)
     
            self.barre = QtGui.QProgressBar(self)
            self.barre.setRange(0, 100)
     
            self.barre.setValue(0)
     
            posit = QtGui.QGridLayout()
            posit.addWidget(self.depart, 0, 0)
            posit.addWidget(self.arret, 1, 0)
            posit.addWidget(self.barre, 2, 0)
            self.setLayout(posit)        
     
            self.operationlongue = None
     
        #========================================================================
        def lancement(self, ok):
     
            if self.operationlongue==None or not self.operationlongue.isRunning():
                # initialisation de la barre de progression
                self.barre.reset()
                self.barre.setRange(0, 100)
                self.barre.setValue(0)
                # démarre l'opération longue dans le thread
                self.operationlongue = Operationlongue()
                self.operationlongue.info.connect(self.progression)
                self.operationlongue.fini.connect(self.stop)
                self.operationlongue.start()
     
        #========================================================================
        @QtCore.pyqtSlot(int)
        def progression(self, i):
            """lancé à chaque réception d'info émis par le thread"""
            self.barre.setValue(i)
            QtCore.QCoreApplication.processEvents() # force le rafraichissement
     
        #========================================================================
        @QtCore.pyqtSlot()
        def arreter(self):
            """pour arrêter avant la fin"""
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.arreter()
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def stop(self, fin):
            """Lancé quand le thread se termine"""
            if fin:
                # fin anticipée demandée
                QtGui.QMessageBox.information(self,
                    u"Opération longue",
                    u"Arrêt avant la fin!")
            else:    
            # fin normale
                self.barre.setValue(100)
                QtGui.QMessageBox.information(self,
                    u"Opération longue",
                    u"Terminée!")
     
        #========================================================================
        def closeEvent(self, event):
            """lancé à la fermeture de la fenêtre quelqu'en soit la méthode"""
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.terminate()
            event.accept()
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    2- l'autre solution qui est moins bonne, voire déconseillée dans la doc, mais qui fonctionne est d'utiliser ".terminate()": il s'agit d'un arrêt "sauvage" du thread, et il n'y a aucune chance de récupérer des données valides du thread lorsqu'il est arrêté comme ça. On utilise ça quand on ne sait pas faire autrement. A titre d'exemple, c'est ce que j'ai utilisé dans le "closeEvent", au cas où l'utilisateur arrêterait le programme en cliquant sur la croix rouge en haut de la fenêtre.

    A noter qu'il y a toujours des précautions à prendre vis à vis d'un utilisateur qui clique sur n'importe quoi "pour voir": les tests avec "self.operationlongue!=None" ainsi qu'avec ".isRunning" permettent d'empêcher, par exemple, d'arrêter un thread qui n'est pas en cours d'exécution, ou de relancer un thread qui s'exécute déjà.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  10. #10
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    Comme je le pensais il est plus simple de vérifier une variable depuis le travail en cours.

    Je passe le sujet en résolu.

    Le temps de faire mes tests et autres et si j'ai un problème je reviendrai poster ici

    Merci à vous tous !
    Sous Kubuntu 20.04

  11. #11
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2013
    Messages : 89
    Points : 91
    Points
    91
    Par défaut
    => Et c'est min setMinimum qu'il faut mettre à 0 (teste sur qtdesigner tu verras le resultat directement )
    C'est bel et bien ce que je te disais car ton exemple avait un setMaximum(0) puis un set Maximum(100). Moi j'aurai mis un setMinimum(0) puis un setMaximum(100). Mais ce n'est qu'un détail l'important est que cela fonctionne et en plus, tes écueils me font progresser moi aussi.

    Parfait pour ta boucle.

  12. #12
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    oups, c'est bien setMaximum qu'il faut mettre à 0 :p
    met le minimum et maximum a 0 et regarde ce qu'il se passe
    Sous Kubuntu 20.04

  13. #13
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2013
    Messages : 89
    Points : 91
    Points
    91
    Par défaut
    Okay, I'll do it soon.

  14. #14
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Juste un petit complément concernant les threads et concernant l'accès à des données communes.

    L'un des avantages des threads par rapport aux processus, c'est le partage des données. En contrepartie, il faut éviter que 2 threads (y compris le programme principal) n'accèdent à la même donnée simultanément. Pour cela, on utilise un verrou (verrou=QMutex()). Ainsi, chaque accès à une donnée commune par chaque thread:
    - sera précédé par la fermeture du verrou (verrou.lock()), en attendant éventuellement que ce verrou soit ouvert.
    - sera suivi par la réouverture du verrou (verrou.unlock())
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  15. #15
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    Une question un peu annexe met en lien avec le code que tu m'as donné.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        def closeEvent(self, event):
            """Lancé à la fermeture de la fenêtre quelqu'en soit la méthode."""
            if self.WorkInProgressVar != None and self.WorkInProgressVar.isRunning():
                self.WorkInProgressVar.terminate() # Arret du travail en cours
            event.accept()
    Lorsque je quitte ton exemple, la fonction est bien lancée avant la fermeture (testé avec un print).

    Mais si je veux l'utiliser sur mon programme, la fonction n'est pas executée.
    Cela est-il lié au fait que j'utilise qtdesigner ?
    car j'ai fait quelques tests et la fonction ne semble pas appelée (pas de retour des print...).
    Sous Kubuntu 20.04

  16. #16
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    closeEvent est une méthode de QWidget (et donc aussi de QMainWindow) qui est appelée systématiquement lors de la fermeture de la fenêtre, quelque soit la méthode utilisée. On la surcharge en général pour "faire le ménage".

    C'est là où il faut vérifier que les fichiers ouverts sont fermés, que les données sont sauvegardées si nécessaires, que les ressources pour les bases de données sont bien libérées, que les fenêtres ouvertes par cette fenêtre sont bien fermées, que les threads sont arrêtés, etc...

    On peut d'ailleurs demander à l'utilisateur si c'est vraiment ce qu'il veut, et si non, d'empêcher la fermeture avec event.ignore().

    Plutôt que print, essaie un messagebox au début de closeEvent. Du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            QtGui.QMessageBox.information(self,
                    u"Information",
                    u"Fermeture de la fenêtre!")
    Il m'est déjà arrivé de constater que les print ne passent pas toujours à l'intérieur du code du GUI. J'imagine que le sys.stdout doit être masqué à ce moment-là?

    A noter que, c'est moins connu, la fenêtre fermée n'est pas entièrement détruite en mémoire. Si on veut la détruire complètement, on peut le demander à l'appel de cette fenêtre comme suit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            self.fenetre.setAttribute(QtCore.Qt.WA_DeleteOnClose)
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  17. #17
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    C'est exactement l’intérêt que j'y voyais à cette fonction

    Mais je confirme, pas de message d'info...
    C'est etrange car ca marche dans ton exemple...

    une idée du pourquoi ?

    si besoin je peux joindre mon script
    Sous Kubuntu 20.04

  18. #18
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Tu as essayé le messagebox?
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  19. #19
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    oui oui bien sur
    j'ai lu avec attention ton post.
    Sous Kubuntu 20.04

  20. #20
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Alors, il y a un os dans ton code: l'arrêt d'une fenêtre DOIT se terminer par ce closeEvent. J'ai bien regardé dans la doc, et on n'y mentionne aucune échappatoire.

    Donne ton code (s'il n'est pas trop long).
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

Discussions similaires

  1. Réponses: 7
    Dernier message: 01/09/2010, 13h27
  2. Wpf/C# Bloquer interaction GUI pendant animation
    Par gomezmic dans le forum Windows Presentation Foundation
    Réponses: 7
    Dernier message: 17/02/2010, 17h04
  3. [XL-97] UserForm : comment ne pas bloquer le code appelant?
    Par Penegal dans le forum Macros et VBA Excel
    Réponses: 31
    Dernier message: 17/04/2009, 15h35
  4. [Conception] Comment faire pour bloquer une valeur pendant 24H
    Par lolodelp dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 07/07/2006, 15h46
  5. [API]Comment ne pas bloquer la fenêtre principal...
    Par X-K4l1 dans le forum Windows
    Réponses: 1
    Dernier message: 16/08/2005, 14h10

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