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 :

Problème avec focusOutEvent sur QLineEdit [QtCore]


Sujet :

PyQt Python

  1. #1
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    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 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut Problème avec focusOutEvent sur QLineEdit
    Bonjour,

    J'aimerais que la perte de focus d'un QLineEdit déclenche une méthode pour traiter l'évènement.

    J'y arrive, et la méthode est effectivement appelée, mais si le focus est effectivement déplacée sur le widget suivant, il en reste des morceaux sur le précédent: on a donc un caret sur le 2ème lineEdit, mais le 1er l'a toujours! Et si j'essaye de passer de l'un à l'autre avec tab, le texte du 1er line Edit reste sélectionné. Manifestement, il y a un problème.

    Voilà un petit code simplifié (Python 2.7) qui montre le pb:

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    class Fenetre(QtGui.QWidget):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.setWindowTitle("Code test")
     
            # créer le lineEdit
            self.lineEdit = QtGui.QLineEdit(self)
     
            # faire que la perte de focus exécute la méthode focusOut
            self.lineEdit.focusOutEvent = self.focusOut
     
            # création d'un 2ème lineEdit
            self.lineEdit2 = QtGui.QLineEdit(self)
     
            # positionnement des 2 widget dans la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.lineEdit, 0, 0)
            posit.addWidget(self.lineEdit2, 1, 0)
            self.setLayout(posit)
     
        def focusOut(self, event):
            self.lineEdit2.setText(u"perte de focus")
            event.accept()
     
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('plastique'))
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Il vient une petite fenêtre avec 2 QLineEdit. Vous rentrez quelque chose dans le 1er: 'azerty' par exemple. Et vous cliquez sur le 2ème QLineEdit.
    La méthode affiche "perte de focus" comme prévu, mais un carret reste visible sur le 1er QLineEdit. Essayez ensuite de passer de l'un à l'autre avec tab.

    Quelqu'un sait-il comment rendre cela normal, où est-ce un bug???

    Merci d'avance.

    Tyrtamos
    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

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,
    Je n'ai peut être pas tout compris mais le cas d'utilisation est du style:
    "l'utilisateur commence à entrer un champ... et on veut scotcher le focus dans la ligne tant qu'il ne nous a pas retourner une valeur attendue."

    focusOutEvent va permettre d'intercepter la sortie de la boîte (même via <TAB>) et de décider:
    - l'entrée n'est pas valide et on va appeler self.setFocus()
    - sinon on passe l'event au parent pour qu'il sorte "proprement".
    A défaut, on a intercepté focusOutEvent mais sans appeler le parent, l'état est zarbi.

    => il est préférable de sous classer QLineEdit, overloader son focusOutEvent, et appeler le parent avant d'en sortir (ou setFocus sinon).
    Genre:
    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
    from __future__ import division
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    class MyLineEdit(QtGui.QLineEdit):
     
        def focusOutEvent(self, event):
            print u"perte de focus"
            super(MyLineEdit, self).focusOutEvent(event)
     
    class Fenetre(QtGui.QWidget):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.setWindowTitle("Code test")
     
            # créer le lineEdit
            self.lineEdit = MyLineEdit(self)
     
            # création d'un 2ème lineEdit
            self.lineEdit2 = QtGui.QLineEdit(self)
     
            # positionnement des 2 widget dans la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.lineEdit, 0, 0)
            posit.addWidget(self.lineEdit2, 1, 0)
            self.setLayout(posit)
     
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('plastique'))
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

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

    Bravo, ça marche!

    J'ai corrigé mon 1er code qui fait maintenant exactement ce que je souhaitais.

    J'ai complété un peu la nouvelle classe héritée de QLineEdit:

    - en passant le parent à l'initialisation pour que la méthode surchargée focusOutEvent puisse écrire dans les autres widgets

    - en ajoutant un focusInEvent qui fonctionne aussi parfaitement.

    Voilà le code corrigé:

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    class MyLineEdit(QtGui.QLineEdit):
        def __init__(self, parent=None):
            super(MyLineEdit, self).__init__(parent)
            self.parent = parent
     
        def focusOutEvent(self, event=None):
            super(MyLineEdit, self).focusOutEvent(event)
            self.parent.lineEdit2.setText(u"perte de focus de la 1ère ligne")
     
        def focusInEvent(self, event=None):
            super(MyLineEdit, self).focusInEvent(event)
            self.parent.lineEdit2.setText(u"reprise de focus de la 1ère ligne")
     
    class Fenetre(QtGui.QWidget):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.setWindowTitle("Code test")
     
            # créer le lineEdit
            self.lineEdit = MyLineEdit(self)
     
            # créer le 2ème lineEdit
            self.lineEdit2 = QtGui.QLineEdit(self)
     
            # positionnement des 2 widget dans la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.lineEdit, 0, 0)
            posit.addWidget(self.lineEdit2, 1, 0)
            self.setLayout(posit)
     
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('plastique'))
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Merci encore!

    Tyrtamos
    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

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

    J'ai complété un peu la nouvelle classe héritée de QLineEdit:
    - en passant le parent à l'initialisation pour que la méthode surchargée focusOutEvent puisse écrire dans les autres widgets
    - en ajoutant un focusInEvent qui fonctionne aussi parfaitement.
    Le parent était déjà passé à l'initialisation!
    Et on peut le récupérer via self.parent() au cas où.
    Ceci dit, l'esprit du bazar serait plutôt publish/suscribe! i.e. plutôt que d'avoir lineEdit devant connaitre père et lineEdit2, on peut lui faire emettre des events avec des paramètres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from PyQt4.QtCore import SIGNAL
     
    class MyLineEdit(QtGui.QLineEdit):
     
        def focusOutEvent(self, event=None):
            self.emit(SIGNAL('focusChange'), u"perte de focus de la 1ère ligne")
            super(MyLineEdit, self).focusOutEvent(event)
     
        def focusInEvent(self, event=None):
            self.emit(SIGNAL('focusChange'), u"reprise de focus de la 1ère ligne")
            super(MyLineEdit, self).focusInEvent(event)
    Puis on comme setText est un SLOT, il suffit de relier le SIGNAL au SLOT, du tissage quoi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            # créer le lineEdit
            le = self.lineEdit = MyLineEdit(self)
     
            # créer le 2ème lineEdit
            le2 = self.lineEdit2 = QtGui.QLineEdit(self)
            self.connect(le, SIGNAL('focusChange'), le2.setText)
    Comme çà personne n'a à connaître qui que ce soit...
    - 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 462
    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 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Citation Envoyé par wiztricks Voir le message
    Le parent était déjà passé à l'initialisation!
    Et on peut le récupérer via self.parent() au cas où.
    Effectivement, avec self.parent(), je peux supprimer le __init__ de la classe MyLineEdit.

    Sinon, merci pour la solution avec emit et SIGNAL: ça marche très bien aussi, et ça permet de ne pas mettre de noms d'autres widgets à l'intérieur de la classe MyLineEdit, et donc de la rendre réutilisable pour d'autres projets. C'est très élégant, même si c'est un peu moins lisible sur le code.

    Merci!

    Tyrtamos
    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 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 752
    Points
    1 752
    Par défaut
    Bonjour.

    Excusez ma flemme mais elle réclame un code tout en un avec la dernière modification. Est-ce possible ? Ce serait sympa.

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

    Y a qu'à demander:

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
     
    import sys
    from PyQt4 import QtCore, QtGui
    from PyQt4.QtCore import SIGNAL
     
    #############################################################################
    class MyLineEdit(QtGui.QLineEdit):
     
        def focusOutEvent(self, event):
            self.emit(SIGNAL('focusChange'), u"perte de focus de la 1ère ligne")
            super(MyLineEdit, self).focusOutEvent(event)
     
        def focusInEvent(self, event):
            self.emit(SIGNAL('focusChange'), u"reprise de focus de la 1ère ligne")
            super(MyLineEdit, self).focusInEvent(event)
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.setWindowTitle(u"Code test")
     
            # créer le 1er lineEdit
            self.lineEdit = MyLineEdit(self)
     
            # créer le 2ème lineEdit
            self.lineEdit2 = QtGui.QLineEdit(self)
     
            # exécute le slot 'setText' de  self.lineEdit2 en cas de réception 
            # du SIGNAL 'focusChange' émit par self.lineEdit
            self.connect(self.lineEdit, SIGNAL('focusChange'), self.lineEdit2.setText)
     
            # positionnement des 2 widgets dans la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.lineEdit, 0, 0)
            posit.addWidget(self.lineEdit2, 1, 0)
            self.setLayout(posit)
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('plastique'))
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Tyrtamos
    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 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 752
    Points
    1 752
    Par défaut
    Ma flemme te remercie grandement.

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

    La solution précédente, redéfinir une nouvelle classe MyLineEdit héritée de QLineEdit, me pose tout de même un problème: j'utilise QtDesigner pour dessiner mes fenêtres.

    Je sais qu'on peut ajouter des widgets 'customisés' à QtDesigner, mais ça dépasse encore mes connaissances.

    Alors, j'ai trouvé une autre solution: ajouter un filtrage d'évènement. Cette solution comporte 2 parties:

    1- l'installation du filtrage d'évènement avec "self.lineEdit.installEventFilter(self)"

    2- la méthode "eventFilter(self, obj, event)" qui récupère l'évènement event et l'objet concerné obj.

    Voilà le nouveau code qui utilise cette technique:

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.setWindowTitle(u"Code test")
     
            # créer le 1er lineEdit
            self.lineEdit = QtGui.QLineEdit(self)
     
            # installation d'un filtrage d'évènement pour lineEdit
            self.lineEdit.installEventFilter(self)
     
            # créer le 2ème lineEdit
            self.lineEdit2 = QtGui.QLineEdit(self)
     
            # créer un 3ème lineEdit
            self.lineEdit3 = QtGui.QLineEdit(self)
     
            # positionnement des 3 widgets dans la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.lineEdit, 0, 0)
            posit.addWidget(self.lineEdit2, 1, 0)
            posit.addWidget(self.lineEdit3, 2, 0)
            self.setLayout(posit)
     
        def eventFilter(self, obj, event):
            if obj == self.lineEdit:
                if event.type() == QtCore.QEvent.FocusOut:
                    self.lineEdit3.setText(u"perte de focus 1ère ligne")
                elif event.type() == QtCore.QEvent.FocusIn:
                    self.lineEdit3.setText(u"reprise de focus 1ère ligne")
            return False
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('plastique'))
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Ça a l'air de marcher, et je n'ai pas encore trouvé d'inconvénient.

    Tyrtamos
    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
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,
    Citation Envoyé par tyrtamos Voir le message
    Ça a l'air de marcher, et je n'ai pas encore trouvé d'inconvénient.
    Ce n'est qu'une histoire de philosophies différentes .

    Dans le premier exemple, on overloade les events qui arrivent au Widget pour lui faire émettre des Signaux qui seront "récupérés" ou pas par d'autres Widgets: les différents Widgets n'ont pas besoin de se connaître.

    Avec un event filter, "on trie" les "events" avant qu'il ne soient propagés à l'objet. De fait, le Widget qui attrape les events doit avoir une connaissance d'un sous ensemble des Widget existant pour faire sa police.

    Je sais qu'on peut ajouter des widgets 'customisés' à QtDesigner, mais ça dépasse encore mes connaissances
    .
    Tu cliques sur l'objet dans l'inspecteur, et ca propose "promouvoir"...
    Puis, on ajoute de nouveaux signaux...
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

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

Discussions similaires

  1. [XI] problème avec groupe sur un champ trié par origine ?
    Par kikidrome dans le forum SAP Crystal Reports
    Réponses: 6
    Dernier message: 11/04/2007, 15h31
  2. problème avec select sur onchange
    Par Kerod dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 01/12/2005, 14h05
  3. Problèmes avec INTERSECT sur MYSQL
    Par zarbydigital dans le forum Requêtes
    Réponses: 1
    Dernier message: 27/09/2005, 13h18
  4. Problème avec OnDrawColumnCell sur un DBGrid
    Par n1portki dans le forum Composants VCL
    Réponses: 3
    Dernier message: 23/09/2005, 04h18
  5. Problème avec RDTSC sur K6-III
    Par le mage tophinus dans le forum x86 32-bits / 64-bits
    Réponses: 17
    Dernier message: 30/09/2003, 09h43

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