[PyQt4] QValidator Frage

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Ich hab einen kleinen Dialog, mit welchem ich aus einer Datenbank (sqlite) selects und inserts mache. Nun möchte ich aber die Eingabe validieren, damit ich je nach Feld nur Zahlen eingeben kann und jedes Feld muss auch befüllt werden. Dass ein Feld nur Zahlen annimmt habe ich bereits hinbekommen. Wie ich aber das Übermitteln von leeren Feldern vermeiden kann, weiss ich (noch) nicht. Leider werde ich aus der Doku nicht wirklich schlau.

Hier mal der Code:

Code: Alles auswählen

class MeinDialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        # UI Datei wird geladen
        self.ui = uic.loadUi("anzeige.ui", self)
        # Slots einrichten
        self.ui.buttonNext.clicked.connect(self.onNext)
        self.ui.buttonBack.clicked.connect(self.onBack)
        self.ui.buttonInsert.clicked.connect(self.onInsert)
        self.ui.linePlz.setValidator(QtGui.QIntValidator(self.linePlz))
    
    def onNext(self):
        query.next()
        id = query.value(0).toInt()[0]
        name = unicode(query.value(1).toString())
        vorname = unicode(query.value(2).toString())
        strasse = unicode(query.value(3).toString())
        plz = query.value(4).toInt()[0]
        ort = unicode(query.value(5).toString())
        #Zuweisung Textfelder
        self.ui.lineID.setText(str(id))
        self.ui.lineName.setText(name)
        self.ui.lineVorname.setText(vorname)
        self.ui.lineStrasse.setText(strasse)
        self.ui.linePlz.setText(str(plz))
        self.ui.lineOrt.setText(ort)
        print id, name, vorname, strasse, plz, ort

    def onBack(self):
        query.previous()
        id = query.value(0).toInt()[0]
        name = unicode(query.value(1).toString())
        vorname = unicode(query.value(2).toString())
        strasse = unicode(query.value(3).toString())
        plz = query.value(4).toInt()[0]
        ort = unicode(query.value(5).toString())
        #Zuweisung Textfelder
        self.ui.lineID.setText(str(id))
        self.ui.lineName.setText(name)
        self.ui.lineVorname.setText(vorname)
        self.ui.lineStrasse.setText(strasse)
        self.ui.linePlz.setText(str(plz))
        self.ui.lineOrt.setText(ort)
        print id, name, vorname, strasse, plz, ort
                
    def onInsert(self):
        name = self.ui.lineName.text()
        vorname = self.ui.lineVorname.text()
        strasse = self.ui.lineStrasse.text()
        ort = self.ui.lineOrt.text()
        plz = self.ui.linePlz.text()
        #self.linePlz.setValidator(QtGui.QIntValidator(self.linePlz))
        #SQL Insert
        query.prepare("INSERT INTO mannschaft (name, vorname, strasse,plz,ort) "
                      "VALUES (?,?,?,?,?)")
        #Wertezuweisung
        query.addBindValue(name)
        query.addBindValue(vorname)
        query.addBindValue(strasse)
        query.addBindValue(plz)
        query.addBindValue(ort)
        query.exec_()
Die Frage ist eben, wie ich eine Eingabe erzwingen kann und eventuell auch Sonderzeichen verbieten kann.

mfg
Zuletzt geändert von Anonymous am Donnerstag 6. Dezember 2012, 11:22, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
lunar

Nutze QRegExpValidator. "QRegExpValidator(QRegExp('.+'))" beispielsweise erzwingt die Eingabe mindestens eines Zeichens. Die Syntax regulärer Ausdrücke ist der Beschreibung von QRegExp zu entnehmen.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Danke mal für die Info und die Verweise. Leider krieg ich es nicht gebacken. Also der QIntValidator funktioniert bei mir so:

Code: Alles auswählen

self.ui.linePlz.setValidator(QtGui.QIntValidator(self.linePlz))
dann müsste analog der QRegExpValidator in etwa so umgeschrieben werden:

Code: Alles auswählen

self.ui.lineOrt.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp('.+'),self.lineOrt))
Passieren tut aber nichts, d.h., es kann auch ohne Eingabe eine neue Zeile in die DB eingetragen werden. Muss ich die einzelnen Eingabefelder noch mit einer if-Abfrage abfangen und auf 0 überprüfen?
lunar

@lackschuh Was hast Du denn erwartet? Du validierst die Daten in "onInsert()" ja auch nicht. Woher sollte Qt denn wissen, dass es jetzt genau in dieser Methode die Daten validieren und einen Fehler auslösen soll?!

"QValidator" prüft nur während der Eingabe. Bevor Du die Daten aus den Eingabefeldern weiterverarbeitest, musst Du sie nochmals prüfen (wozu Du natürlich die Validatoren der jeweiligen Eingabefelder verwenden kannst). Ich dachte, dass wäre offensichtlich.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

lunar hat geschrieben:"QValidator" prüft nur während der Eingabe. Bevor Du die Daten aus den Eingabefeldern weiterverarbeitest, musst Du sie nochmals prüfen (wozu Du natürlich die Validatoren der jeweiligen Eingabefelder verwenden kannst). Ich dachte, dass wäre offensichtlich.
ja, irgendwie logisch :wink: Dachte nur, dass es in Qt vielleicht irgend etwas einfaches - wie bei HTML das Attribut required - geben würde.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo lunar

Sry dass ich dich nochmals stresse, aber ich krieg's irgendwie nicht gebacken und hoffe, du kannst mir nochmals ein paar Tipps geben. Ich war nun ein paar Abende am probieren, jedoch ohne wirklichen Erfolg. Aus "Verzweigung" hab ich den Code in ein try ... except gepackt, was wahrscheinlich nicht der Sinn ist...

Also zum allgemeinen Verständnis, so dass ich es hoffentlich kapiere:

- ich hab ganz am Anfang in der __init__ Methode meine Validatoren eingefügt (hier sind mal zwei davon).

Code: Alles auswählen

self.ui.linePlz.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp("[0-9]+"),self.linePlz))
self.ui.lineOrt.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp("[aA-zZ. ]"),self.lineOrt))
Während der Eingabe in die Textfelder (QEditLine) überprüft der Validator die Eingabe und lässt entweder die Eingabe zu oder eben nicht. So weit so gut. Nun habe ich eine Methode, welche sich "onInsert" nennt. Diese wird aufgerufen, sobald man den push-Button "buttonInsert" drückt. Hier fängt meine Bescheidenheit an.

Nun muss ich die Textfelder nochmals überprüfen, bevor mittels push-Button die Werte in de DB eingetragen werden. D.h., die Felder sollen alle ausgefüllt sein. Dazu hast du mir geraten, die obgennanten Validatoren zu verwenden. Leider weiss ich nicht, wie ich das bewerkstelligen soll... Ich hab das fälschlicherweise mal so gemacht:

Code: Alles auswählen

    def onInsert(self,event):
        #Deklarierung der Textfelder
        name = self.ui.lineName.text()
        vorname = self.ui.lineVorname.text()
        strasse = self.ui.lineStrasse.text()
        plz = self.ui.linePlz.text()
        ort = self.ui.lineOrt.text()
        #Meldung, wenn ein Feld leer ist
        try:
            plz = int(plz)
        except ValueError:
            msgBox = QtGui.QMessageBox.warning(self,'Achtung!',u"Bitte folgendes Feld korrekt ausfüllen: PLZ",QtGui.QMessageBox.Ok)
        else:
            print "name:", name, "vorname:", vorname, "strasse:", strasse, "plz:", plz, "ort:", ort
            safe = QtGui.QMessageBox.question(self, 'Speichern?',
            u'Name: %s\nVorname: %s\nStrasse: %s\nPLZ: %s\nOrt: %s\n' % (name,vorname,strasse,plz,ort), QtGui.QMessageBox.Yes | 
            QtGui.QMessageBox.No)
            if safe == QtGui.QMessageBox.Yes:
                #SQL Insert
                query.prepare("INSERT INTO mannschaft (name, vorname, strasse,plz,ort) "
                              "VALUES (?,?,?,?,?)")
                #Wertezuweisung
                query.addBindValue(name)
                query.addBindValue(vorname)
                query.addBindValue(strasse)
                query.addBindValue(plz)
                query.addBindValue(ort)
                query.exec_()
            else:
                print "Dialog wurde geschlossen"
                event.ignore()
Noch zwei zusätzliche Fragen:
- was muss ich bei den regulären Ausdrücken ergänzen, damit ich auch Umlaute wie ö ü ä é einfügen kann?
- eine andere Möglichkeit wäre, dass der push-Button "buttonInsert" gesperrt wird und erst dann, wenn alle Felder ausgefüllt wurden auf "enable" gesetzt wird. Ich hab sowas schon einmal gesehen, leider weiss ich die Seite nicht mehr wo so ein Beispiel aufgezeigt wurde. <-- wie könnte ich grob gesagt so etwas umsetzen?

PS:
Sei bitte nicht zu streng mit mir, denn von 6 Monaten dachte ich beim Namen dieser tollen Sprache ausschliesslich an ein Reptil :wink:
lunar

@lackschuh Über ".validator()"-Methode eines Steuerelements erhältst Du den zugehörigen Validator, und über dessen ".validate()"-Methode kannst Du den Wert eines Steuerelements prüfen. Speziell bei "QLineEdit" kannst Du auch ".hasAcceptableInput()" verwenden, e.g. "if self.ui.lineOrt.hasAcceptableInput(): print('Ort ist gültig')".

Natürlich solltest Du auch den Knopf deaktivieren, solange nicht alle Felder gültige Eingaben haben. Verwende dazu das Signal ".textEdited()" der Textfelder, um darauf zu reagieren, wenn ein Textfeld bearbeitet wurde, überprüfe dann, ob alle Eingaben gültig sind, und (de-)aktiviere den Knopf entsprechend.

Code: Alles auswählen

def __init__(self, parent=None):
    # ...
    self.buttonInsert.setEnabled(False)
    self.lineOrt.textEdited.connect(self.checkInputs)
    self.linePlz.textEdited.connect(self.checkInputs)
    # analog für alle weiteren Eingabefelder

@pyqtSlot
def updateInsertButton(self):
    self.buttonInsert.setEnabled(w.hasAcceptableInput() for w in [self.lineOrt, self.linePlz, ...])
Um auch Umlaute zu erlauben, kannst Du den regulären Ausdruck "QRegExp(r'\w')" verwenden.
Antworten