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 :

Timer qui fonctionne encore si fermeture fenêtre fille via bouton perso


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Inscrit en
    Avril 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 33

    Informations forums :
    Inscription : Avril 2009
    Messages : 10
    Par défaut Timer qui fonctionne encore si fermeture fenêtre fille via bouton perso
    Hello tout le monde,

    Je suis face à un soucis dont je n'arrive pas à trouver la solution, j'ai beau chercher, je ne trouve rien qui m'aide....

    J'ai donc mon programme principale, avec une fenêtre (pyqt), j'ai notamment un timer qui vient lire le port série.
    Ce prog principale ouvre une fenêtre fille dans certaines conditions, cette fenêtre fille a aussi un timer et vient lire le port série de la fenêtre parent.

    Jusque là, pas de soucis.

    Si je ferme la fenêtre fille via la croix, il ne semble pas y avoir de soucis, mais si je ferme via le code / un bouton qui appel "self.close()", c'est là le soucis :
    La fenêtre se ferme bien, mais le timer fonctionne encore et donc la fenêtre fille, que l'on ne voit plus, arrive encore à lire le port série... ce qui donc vient "voler" des datas port série au progr principal. Si je ferme la fenêtre avec la croix, pas de soucis.


    Depuis la fenêtre principale, je lance la fenêtre enfant comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     self._start_window = Dialog(parent=self)
     self._start_window.exec()
    Sur la fenetre enfant, j'ai tenté ça, mais rien n'y fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        def closeEvent(self, evt):
            print("Children closed")
            self.timer2.stop()
    Savez-vous comment je peux résoudre ce soucis ?

    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,

    Intrigué par la question, j'ai fait un petit code de test, et je ne rencontre pas le problème: le timer s'arrête dès que la fenêtre secondaire QDialog se ferme, quelque soit la méthode de fermeture utilisée.

    Voilà ce code test (à lancer dans une console pour voir l'affichage du print):

    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
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import sys
    import os
     
    from PyQt5 import (QtWidgets, QtGui, QtCore)
     
    #############################################################################
    class Dialogue(QtWidgets.QDialog):
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.bouton = QtWidgets.QPushButton("Quitter", self)
            self.bouton.clicked.connect(self.quitter)
     
            layout = QtWidgets.QGridLayout()
            layout.addWidget(self.bouton, 0, 0)
            self.setLayout(layout)
     
            self.compteur = 0
     
            # lancement du timer
            self.timer = QtCore.QTimer(self)
            self.timer.setTimerType(QtCore.Qt.PreciseTimer)
            self.timer.setInterval(500)
            self.timer.timeout.connect(self.action)
            self.timer.start()
     
        #========================================================================
        def action(self):
            """méthode lancée par le timer
            """
            self.compteur += 1
            print(self.compteur)
     
        #========================================================================
        def quitter(self):
            """méthode lancée par le bouton "quitter"
            """
            print("Quitter")
            self.close() # demande de fermeture de la fenêtre
     
        #========================================================================
        def closeEvent(self, event=None):
            """méthode lancée par la fermeture de la fenêtre dans tous les cas
            """
            print("Fermeture")
            self.timer.stop() # Stoppe le timer
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
     
            self.bouton1 = QtWidgets.QPushButton("bouton", self)
            self.bouton1.clicked.connect(self.clictest)
     
            posit = QtWidgets.QGridLayout()
            posit.addWidget(self.bouton1, 0, 0)
            self.setLayout(posit)
     
        #========================================================================
        def clictest(self):
            """ lancement de la fenêtre QDialog
            """
            self.dialog = Dialogue()
            self.dialog.exec_() # <= boucle de traitement des évènements spécifique au QDialog
     
    #############################################################################
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
     
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    A comparer ce code avec celui qui pose problème!

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par H3xor Voir le message
    Sur la fenetre enfant, j'ai tenté ça, mais rien n'y fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        def closeEvent(self, evt):
            print("Children closed")
            self.timer2.stop()
    Est-ce que tu vois "Children closed" apparaitre dans la console quand tu fermes la fenêtre ? Parce que sinon ça veut dire que la fonction n'est pas appelée...

    Citation Envoyé par tyrtamos Voir le message
    Intrigué par la question, j'ai fait un petit code de test, et je ne rencontre pas le problème: le timer s'arrête dès que la fenêtre secondaire QDialog se ferme, quelque soit la méthode de fermeture utilisée.
    C'est autorisé d'appeler exec_() pour une sous-fenêtre? Moi généralement mes sous-fenêtres je les affiche via show() ou open() (la différence est minime, open() l'ouvre en mode modal forcé tandis que show() l'ouvre et lui applique la modalité que la fenêtre désire via setModal()). Accessoirement si je reprends ton code et que je remplace exec_() par show() ça marche pareil.

    Toutefois pour le closeEvent() je prendrais la précaution de rajouter quelque part (probablement à la fin) un super().closeEvent(event) pour ne pas perdre les actions du closeEvent() d'origine.

    En fait, comme le PO parle de deux timers (un dans la fenêtre principale et un dans la sous-fenêtre) j'ai enrichi ton propre code pour reproduire ce détail...
    Code python : 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
    #!/usr/bin/python3
    # coding: utf-8
     
    import sys
    import os
     
    from PyQt5 import (QtWidgets, QtGui, QtCore)
     
    #############################################################################
    class Dialogue(QtWidgets.QDialog):
     
    	#========================================================================
    	def __init__(self, parent=None):
    		super().__init__(parent)
     
    		self.bouton = QtWidgets.QPushButton("Quitter", self)
    		self.bouton.clicked.connect(self.quitter)
     
    		layout = QtWidgets.QGridLayout()
    		layout.addWidget(self.bouton, 0, 0)
    		self.setLayout(layout)
     
    		# lancement du timer
    		self.compteur = 0
    		self.timer = QtCore.QTimer(self)
    		self.timer.setTimerType(QtCore.Qt.PreciseTimer)
    		self.timer.setInterval(250)
    		self.timer.timeout.connect(self.action)
    		self.timer.start()
     
    	#========================================================================
    	def action(self):
    		"""méthode lancée par le timer
                    """
    		self.compteur += 1
    		print("ss: ", self.compteur)
     
    	#========================================================================
    	def quitter(self):
    		"""méthode lancée par le bouton "quitter"
                    """
    		print("Quitter")
    		self.close() # demande de fermeture de la fenêtre
     
    	#========================================================================
    	def closeEvent(self, event):
    		"""méthode lancée par la fermeture de la fenêtre dans tous les cas
                    """
    		print("Fermeture fenêtre")
    		self.timer.stop() # Stoppe le timer
    		super().closeEvent(event)
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
    	#========================================================================
    	def __init__(self, parent=None):
    		super(Fenetre, self).__init__(parent)
     
    		self.bouton1 = QtWidgets.QPushButton("bouton", self)
    		self.bouton1.clicked.connect(self.clictest)
     
    		posit = QtWidgets.QGridLayout()
    		posit.addWidget(self.bouton1, 0, 0)
    		self.setLayout(posit)
     
    		# lancement du timer
    		self.compteur = 0
    		self.timer = QtCore.QTimer(self)
    		self.timer.setTimerType(QtCore.Qt.PreciseTimer)
    		self.timer.setInterval(500)
    		self.timer.timeout.connect(self.action)
    		self.timer.start()
     
    	#========================================================================
    	def clictest(self):
    		""" lancement de la fenêtre QDialog
                    """
    		self.dialog = Dialogue()
    		self.dialog.show() # <= boucle de traitement des évènements spécifique au QDialog
     
    	#========================================================================
    	def action(self):
    		"""méthode lancée par le timer
                    """
    		self.compteur += 1
    		print("main: ", self.compteur)
     
    	#========================================================================
    	def closeEvent(self, event):
    		"""méthode lancée par la fermeture de la fenêtre dans tous les cas
                    """
    		print("Fermeture appli")
    		self.timer.stop() # Stoppe le timer
    		super().closeEvent(event)
     
    #############################################################################
    if __name__ == "__main__":
    	app = QtWidgets.QApplication(sys.argv)
     
    	fen = Fenetre()
    	fen.show()
    	sys.exit(app.exec_())

    Pareil, aucun souci de rémanence. Au lancement de l'appli le main timer démarre. Si la sous-fenêtre est appelée un second timer deux fois plus rapide démarre en parallèle qui s'arrête à la fermeture tandis que le main timer lui continue son chemin.

    A suivre...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    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 Sve@r

    Citation Envoyé par Sve@r Voir le message
    C'est autorisé d'appeler exec_() pour une sous-fenêtre?
    Ce n'est pas parce que c'est une sous-fenêtre mais que c'est une QDialog (d'ailleurs, exec_() n'existe pas dans une QWidget). J'ai pris l'habitude d'utiliser exec_() avec les QDialog, mais un open() (ou un show() avec une instruction modal) convient très bien aussi, et peut même être recommandé (voir le doc). La différence importante est que exec_() lance une boucle spécifique de traitement des évènements qui peut être utile, alors que open() et show() sont plus simples.

    Extrait de la doc de Qt5 concernant exec() de QDialog:
    https://doc.qt.io/qt-5/qdialog.html#exec

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Salut tyrtamos

    Depuis que j'ai lu ton post je cherche désespérément à voir une différence entre exec_() et open(). Et je n'en vois pas et ça me désespère.

    Parce que quand j'ai plusieurs possibilités offertes, je veux toujours choisir en toute connaissance de cause. Au début pour ouvrir une sous-fenêtre j'utilisais show(). Puis j'ai découvert open() et là est alors venu un premier dilemne à savoir laquelle choisir et surtout pourquoi. Mais les différences entre les deux méthodes m'étant apparues assez vite, maintenant je sais laquelle prendre quand je dois ouvrir une sous-fenêtre.

    Et voilà qu'arrive cette nouvelle possibilité et de nouveau rebelote, sauf que là les différences je ne les vois pas.

    As-tu un exemple où on verrait un comportement différent entre exec_() et open()/show() ?
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    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 Sve@r

    A ma connaissance, les principales différences pour QDialog sont:

    - exec_(): utilise le mode "modal", affiche le dialogue, et crée une boucle spécifique de traitement des évènements (différente donc de celle de l'application app.exec_())

    - open(): utilise le mode "modal" et affiche le dialogue

    - show(): même chose que open mais ne précise pas le mode "modal" (il faut donc ajouter l'instruction si c'est utile).

    Mais ce serait bien si c'était aussi simple... Quand je regarde les exemples du web, il sont comme les miens quasiment tous avec exec_(). Mais quand je regarde la doc de Qt5, je vois que l'utilisation de exec_() est déconseillée!
    Extrait de la doc de "exec()" du QDialog traduit en français (merci google):

    Remarque : évitez d'utiliser cette fonction ; à la place, utilisez open(). Contrairement à exec(), open() est asynchrone et ne fait pas tourner une boucle d'événement supplémentaire. Cela empêche une série de bogues dangereux de se produire (par exemple, la suppression du parent de la boîte de dialogue alors que la boîte de dialogue est ouverte via exec()). Lorsque vous utilisez open(), vous pouvez vous connecter au signal finish() de QDialog pour être averti lorsque la boîte de dialogue est fermée.
    En plus, le cas des QFileDialog, qui héritent de QDialog, est un peu différent: open a reçu une autre signification!

    Il me semble avoir rencontré des cas ou j'utilisais la propriété spécifique de exec_(), mais je n'arrive plus à mettre la main dessus. En tout cas, j'aime bien que les outils que j'utilise soient "étanches" car je n'aime pas les effets de bord. De ce fait, je continue à utiliser exec_(), tant pour les QDialog que pour les QFileDialog, en veillant à échapper au piège signalé par la doc de Qt5.

    Mais si tu veux suivre les recommandations de la doc pour des QDialog, utilise open() (ou show avec précision du mode)!

Discussions similaires

  1. Timer qui bloque toutes les autres fenêtres
    Par keunene dans le forum VB.NET
    Réponses: 3
    Dernier message: 18/08/2017, 16h36
  2. [AC-2016] mystère, état disparu qui fonctionne encore!
    Par djibouli dans le forum IHM
    Réponses: 3
    Dernier message: 29/04/2017, 16h37
  3. fermeture fenêtre fille
    Par patrice.darlet dans le forum GTK+
    Réponses: 3
    Dernier message: 02/10/2009, 15h27
  4. Attente fermeture fenêtre fille pour action
    Par padawan31 dans le forum Général JavaScript
    Réponses: 11
    Dernier message: 14/06/2007, 10h08
  5. fenêtre fille qui reste au premier plan
    Par parabolus dans le forum Windows Forms
    Réponses: 8
    Dernier message: 02/04/2007, 18h02

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