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 :

QValidator: problèmes avec certaines valeurs [QtGui]


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut QValidator: problèmes avec certaines valeurs
    Bonjour,

    voilà mon problème, j'ai créé une IHM avec un certain nombre de champs de saisie, dont je contrôle le contenu grâce à des QIntValidator et QDoubleValidator.

    Seulement avec les QDoubleValidator, certaines valeurs sont acceptées alors que je ne le voudrais pas:
    "e"
    "-"
    "+"
    passent sans problème! j'accepterais par exemple "-6.3e-4", mais "e" tout seul ça va me poser des soucis pareil pour "-" et "+" tout seuls.

    Je pensais me servir de l’événement focusOutEvent pour remplacer le contenu du champ de saisie par une valeur par défaut si il est mauvais.
    Qu'en pensez-vous? Connaissez-vous de meilleures solutions?
    Merci d'avance pour votre aide.

  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,

    A l'extrème, si validator n'existait pas, il suffirait de déclencher une méthode à la fin de l'édition avec un signal "returnPressed", de vérifier que la chaine se convertit bien en nombre chez Python, et de redonner le focus au lineEdit si ce n'est pas le cas. On pourrait aussi tester la validité du nombre double avec une expression régulière respectant fidèlement la syntaxe Python.

    Mais QValidator a l'avantage d'ajouter des contrôles beaucoup plus poussés à chaque caractère. On n'a donc pas besoin d'attendre la fin d'édition pour savoir si c'est ok. Par exemple, si on a défini qu'il doit y avoir 2 décimales, il est impossible d'en taper une 3ème. Et si on veut terminer l'édition avec seulement un 'e': il y a refus => le focus reste dans le lineEdit.

    Dans mes tests, je ne trouve pas que QDoubleValidator accepte des anomalies comme 'e' ou '+' en tant que nombre valide.

    Voilà un petit code d'essai (Python 2.7, PyQt4):

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    # Python 2.7
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
        #========================================================================
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
     
            self.edit = QtGui.QLineEdit(self)
            self.edit.returnPressed.connect(self.finedit)
     
            self.validouble = QtGui.QDoubleValidator(self)
            self.validouble.setRange(-100.0, +100.0, 2)
            self.edit.setValidator(self.validouble)
     
            posit = QtGui.QGridLayout()
            posit.addWidget(self.edit, 0, 0)
            self.setLayout(posit)
        #========================================================================
        def finedit(self):
            nb = self.edit.text()
            QtGui.QMessageBox.information(self,
                u"Vérification",
                u"nombre: %s" % nb)
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Mais si ça ne suffit pas, on peut toujours sous-classer QDoubleValidator pour en changer le comportement. Voilà un exemple:

    On veut interdire un nombre qui commence par 'e':

    Sous-classement de QDoubleValidator:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Validation(QtGui.QDoubleValidator):
     
        def __init__(self, parent=None):
            super(Validation, self).__init__(parent)
     
        def validate(self, ch, pos):
            """retourne la validation à chaque nouveau caractère"""        
            print pos, ch
            if pos==1 and ch in ['e', 'E']:
                return (QtGui.QValidator.Invalid, pos)
            return QtGui.QDoubleValidator.validate(self, ch, pos)
    Et dans le 1er code, on changera simplement la ligne qui affecte le QDoubleValidator au QLineEdit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.validouble = Validation(self)
    Et c'est tout! Avec ça, il est impossible de taper un 'e' comme 1er caractère du nombre.

    Ok?

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Salut,

    Je dirais "hu?!?".

    Seulement avec les QDoubleValidator, certaines valeurs sont acceptées alors que je ne le voudrais pas:
    Il faudrait montrer la sauce magique qui permet ça!
    QValidator.validate retourne 3 valeurs: Acceptable, Invalid, Intermediate
    Avec "e2" on récupèrera Intermediate.
    Ca se teste assez facilement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from PyQt4.QtGui import QDoubleValidator, QValidator
    states = { 
          QValidator.Acceptable: 'Acceptable',
          QValidator.Invalid: 'Invalid',
          QValidator.Intermediate: 'Intermediate',
        }
    validator = QDoubleValidator()
    for text in '50.2', 'e2':
        rs = validator.validate(text, 0)
        print ('text: ', text, 'state: ', states[rs[0]])
    Mais QValidator a l'avantage d'ajouter des contrôles beaucoup plus poussés à chaque caractère. On n'a donc pas besoin d'attendre la fin d'édition pour savoir si c'est ok.
    QLineEdit n'affiche que les mises a jour pour lesquelles le Validator ne retourne pas "Invalid". "e2" est "Intermediate": on le verra s'afficher.
    Mais l'event returnPressed n'est déclenche que lorsque l’entrée sera "Acceptable".
    C'est une bonne base.

    Si on veut une autre interaction avec l'utilisateur pour lui faire saisir différents LineEdit, la méthode .hasAcceptableInput() permet de savoir si l’entrée est "valide" sans se préoccuper du validateur associe.
    Reste a définir et mettre en place le "dialogue" et ne pas en sortir avec des entrées "invalides" (si c'est ce qu'on veut).
    Exemple simpliste: on crée 3 LineEdit dans un layout et on bloque l'action du <Tab> sur le lineEdit courant.
    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
    from PyQt4.QtGui import (QApplication, QLineEdit,
                             QWidget, QVBoxLayout, QDoubleValidator)
     
    class Widget(QWidget):
       def focusNextPrevChild(self, next):
           w = self.focusWidget()
           if w.hasAcceptableInput():
               layout = self.layout()
               ix = layout.indexOf(w)
               ix = (ix + 1) % layout.count()
               w = layout.itemAt(ix).widget()
           w.setFocus()
           return True
     
    if __name__ == '__main__':
        app = QApplication([])
        widget = Widget()
        layout = QVBoxLayout()
        widget.setLayout(layout)
        validator = QDoubleValidator()
        for _ in range(3):
            edit = QLineEdit(widget)
            edit.setValidator(validator)
            layout.addWidget(edit)
        widget.show()
        app.exec()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut
    Merci pour vos réponses,
    je n'avais pas assez bien lu la doc et pas vu cette histoire d'états "Acceptable", "Intermediate" et "Invalid"...
    J'ai utilisé "hasAcceptableInput" pour obtenir le résultat que je voulais, voici le code:

    Code __init__ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    self.varLineEdit1 = 0
    self.ui.lineEdit1.textChanged[QtCore.QString].connect(self.majLineEdit1)
    self.ui.lineEdit1.setValidator(QtGui.QDoubleValidator(0,float('inf'), 2, self.ui.lineEdit1))
    self.ui.lineEdit1.focusOutEvent = partial(self.valider, self.ui.lineEdit1, 0)

    Code majLineEdit1 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def majLineEdit1(self, valeurChamp)
        '''
        mise a jour de la variable liee au champ de saisie lineEdit1
        - valeurChamp: [QString] contenu du champ de saisie
        '''
        try:
            self.varLineEdit1 = float(str(valeurChamp))
        # Cas valeur "intermediate": on laisse l'utilisateur continuer sa saisie
        except ValueError:
            pass

    Code valider : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def valider(self, lineEdit, defaultValue, event)
        '''
        Evenement de perte du focus d un champ de saisie formaté.
        Valide uniquement le contenu si l etat du QValidator est Acceptable
        et non Intermediate (champ vide, e,  +, ...)
        - lineEdit: [QLineEdit] champ de saisie concerné
        - defaultValue: [float] valeur a utiliser en cas d erreur
        - event: [QEvent] evenement de perte du focus
        '''
        # Acceptation de l'evenement "focus out"
        QtGui.QLineEdit.focusOutEvent(lineEdit, event)
     
        # Utilisation d'une valeur par defaut si l'etat n'est pas "Acceptable"
        if not lineEdit.hasAcceptableInput():
            lineEdit.setText(str(defaultValue))

    Voilà ce code fonctionne parfaitement pour moi, j'avais oublié de préciser que les slots de mes lineEdit fonctionnaient sur textChanged et non returnPressed, en effet j'ai besoin que mes variables se mettent à jour au fur et à mesure que l'utilisateur tape ses valeurs.
    L'appel à setText() dans ma méthode valider() relance le slot du champ de saisie, ce qui permet de mettre à jour la variable avec la valeur par défaut si l'utilisateur a quitté le champ de saisie avec une valeur "Intermediate".

    Merci pour votre aide!

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

Discussions similaires

  1. [Vb.Net]NumericUpDown et DataBinding : problème avec la valeur min
    Par SamRay1024 dans le forum Windows Forms
    Réponses: 3
    Dernier message: 25/04/2006, 16h34
  2. Problème avec certains caractéres dans variable
    Par Off$ide dans le forum Langage
    Réponses: 14
    Dernier message: 13/12/2005, 10h46
  3. Problème avec les valeurs par défaut
    Par Steph Ace dans le forum Requêtes
    Réponses: 3
    Dernier message: 12/12/2005, 09h55
  4. Réponses: 6
    Dernier message: 24/10/2005, 20h12
  5. problème avec une valeur decimal
    Par vbcasimir dans le forum Langage
    Réponses: 2
    Dernier message: 11/10/2005, 13h52

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