Seite 1 von 2

merkwürdiges Verhalten QIntValidator

Verfasst: Dienstag 17. Januar 2012, 19:49
von noisefloor
Hallo,

folgendes Prog funktioniert, aber der Validator verhält sich IMHO komisch:

Code: Alles auswählen

#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~

import sys

from PySide import QtGui

class SimpelQt(QtGui.QDialog):
    def __init__(self,parent=None):
        super(SimpelQt, self).__init__(parent)
        self.setWindowTitle('Simpel Qt')
        layout = QtGui.QVBoxLayout()
        self.eingabe = QtGui.QLineEdit()
        self.eingabe_valid = QtGui.QIntValidator(0,1000,self)
        self.eingabe.setValidator(self.eingabe_valid)
        layout.addWidget(self.eingabe)
        self.button = QtGui.QPushButton(u'Quadrieren')
        layout.addWidget(self.button)
        self.label = QtGui.QLabel(u'Ergebnis...')
        layout.addWidget(self.label)
        self.setLayout(layout)
        self.button.clicked.connect(self.rechnen)

    def rechnen(self):
        wert = int(self.eingabe.text())
        return self.label.setText(unicode(wert*wert))

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    simpel_qt = SimpelQt()
    simpel_qt.show()
    sys.exit(app.exec_())
Gibt man z.B. "1.1" oder "1,1" erhält man als Ergebnis 121, weil der Punkt bzw. das Komma einfach "verschwinden"...

Bug oder Feature? Wenn Feature - was ist dann der Sinn des _Int_-Validators?

Pyside + Qt4 Version ist die aus den Ubuntu Oneiric Quellen.

Gruß, noisefloor

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Dienstag 17. Januar 2012, 19:54
von BlackJack
@noisefloor: Wie gibst Du denn "1.1" ein? Den '.' oder das ',' kannst Du doch gar nicht eingeben? Und genau das ist der Sinn von dem Validator — der Inhalt muss zu *jeder* Zeit einem `int` im Wertebereich entsprechen. Etwas anderes wird gar nicht erst zugelassen.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Dienstag 17. Januar 2012, 20:29
von noisefloor
Hallo,
Etwas anderes wird gar nicht erst zugelassen.
Das dachte ich auch. Aber es wird genommen... Ganz regulär über die Tastatur :?:

Buchstaben werden in der Tat ignoriert.

Kann das jemand bei sich nachvollziehen mit dem obigen Programm?

Gruß, noisefloor

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Dienstag 17. Januar 2012, 21:18
von BlackJack
@noisefloor: Also ich kann es nicht nachvollziehen. Ich kann nur Ziffern eingeben.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 08:51
von noisefloor
Hallo,

strange... Ich kann als _erste_ Eingabe auch keinen Punkt oder Komma machen. Wenn ich zuerst aber eine Zahl eingebe, dann nimmt er . und , ...

Muss das morgen mal unter Windows testen...

Gruß, noisefloor

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 11:59
von JonasR
Unter Windows habe ich das Gleiche. Erste Ziffer muss eine Zahl sein danach kann man einen Punkt oder ein Komma machen. Bei absenden wird aber beides raus genommen.

€ Nach jeder Zahl kann man ein Punkt oder Komma machen.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 12:39
von Hyperion
Ich hab 's unter Unbuntu (Oneiric) getestet und komme ebenfalls zu dem Ergebnis, dass man entweder Punkte oder Kommata eingeben kann - lustiger Weise nicht beides in einem String!

Man kann das auch ohne GUI drum herum testen:

Code: Alles auswählen

In [19]: from PySide import QtGui

In [20]: v = QtGui.QIntValidator(0, 100, None)

In [21]: v.validate("5.6", 0)
Out[21]: (PySide.QtGui.QValidator.State.Intermediate, u'5.6', 0)

In [22]: v.validate("5,6", 0)
Out[22]: (PySide.QtGui.QValidator.State.Intermediate, u'5,6', 0)

In [23]: v.validate("5,.", 0)
Out[23]: (PySide.QtGui.QValidator.State.Invalid, u'5,.', 0)
Ich vermute mal, dass das irgend wie am `locale` liegt...

Ich würde als parent vom Validator übrigens `self.eingabe`, also das zugehörige QLineEdit, wählen. Ändert natürlich nichts am Problem ;-)

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 12:59
von BlackJack
Bei mir sieht das so aus:

Code: Alles auswählen

In [147]: v.validate("5.6", 0)
Out[147]: (PySide.QtGui.QValidator.State.Invalid, u'5.6', 0)
Aber „locale” scheint eine vernünftige Vermutung, wenn man zum Beispiel in einer angelsächsischen „locale” '50.0' oder "1,000,000" als Schreibweisen für ganze Zahlen zulassen würde. Dann müsste auch '.' und ',' in einer Zahl gehen: "4,711.23". Für eine deutsche „locale” müsste man dann die beiden Trennzeichen vertauschen.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 13:08
von Hyperion
Also bei mir klappt das aber so auch nicht:

Code: Alles auswählen

In [61]: from PySide import QtCore

In [62]: loc = QtCore.QLocale()

In [63]: loc.groupSeparator()
Out[63]: u'.'

In [64]: loc.toInt("12")
Out[64]: (12, True)

In [65]: loc.toInt("1.2")
Out[65]: (0, False)

In [66]: loc.numberOptions()
Out[66]: 0
Genau das Verhalten würde ich erwarten - aber der `QIntValidator` verhält sich da ja anders :-(

Auch das Einstellen mittels `setNumberOptions` funzt nicht :-(

Code: Alles auswählen

In [67]: loc.setNumberOptions(QtCore.QLocale.OmitGroupSeparator)

In [68]: loc.toInt("1.2")
Out[68]: (0, False)

In [69]: loc.numberOptions()
Out[69]: 1

In [70]: loc.setNumberOptions(QtCore.QLocale.RejectGroupSeparator)

In [71]: loc.toInt("1.2")
Out[71]: (0, False)

In [72]: loc.numberOptions()
Out[72]: 2
Das wäre jetzt eine Erklärung gewesen, wie der Validator evtl. vorgehen könnte... ist aber leider auch nicht so.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 14:05
von BlackJack
@Hyperion: Was wolltest Du damit jetzt zeigen? Wenn man den „group separator” an einer ungültigen Stelle setzt, dann ist das natürlich auch eine ungültige Zahl. Setz ihn doch mal korrekt.

Code: Alles auswählen

In [155]: loc.groupSeparator()
Out[155]: u','

In [156]: loc.toInt("1,2")
Out[156]: (0, False)

In [157]: loc.toInt('1,200')
Out[157]: (1200, True)

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 14:10
von Hyperion
*patsch* OMG... ja, manchmal hat man ein Brett vorm Kopf :-D

Code: Alles auswählen

In [83]: loc.toInt(u"1.200")
Out[83]: (1200, True)

In [84]: loc.setNumberOptions(QtCore.QLocale.RejectGroupSeparator)

In [85]: loc.toInt(u"1.200")
Out[85]: (0, False)
Ok, das passt dann ja. Damit wäre es wohl eine Lösung, die `NumberOptions` entsprechend zu setzen, wenn man keine Punkte oder Kommata akzeptiert haben will.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 14:41
von JonasR
Ich kann bei mir auch Sachen wie 1,1,1, eingeben... natürlich das gleiche mit Punkten

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 20:14
von noisefloor
Hallo,

bleibt aber die Frage: Ist das ein Bug, den man mal melden sollte?

Gruß, noisefloor

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 20:48
von lunar
@Alle: Dieses Verhalten ist kein Fehler, sondern Feature, und im Übrigen auch dokumentiert. Nur hat hier offenbar niemand die Dokumentation gelesen. Der Sinn von "QIntValidator" ist nicht, einfach nur Ziffern als Eingabe zu akzeptieren. Das wäre trivial (siehe Ende dieses Beitrags). "QIntValidator" ermöglicht eine den Spracheinstellungen entsprechende Eingabe von Zahlen, und mithin auch Tausender-Trennzeichen.

Grundsätzlich kann man in "QIntValidator" dabei sowohl das den Spracheinstellungen entsprechende Eingabeformat nutzen also auch dasjenige der Standard-C-Lokalisierung:
[...] QIntValidator uses its locale() to interpret the number. For example, in Arabic locales, QIntValidator will accept Arabic digits. In addition, QIntValidator is always guaranteed to accept a number formatted according to the "C" locale.
Mithin kann man bei deutscher Spracheinstellung sowohl den Punkt als auch das Komma als Tausender-Trennzeichen nutzen, nicht aber beides gleichzeitig. Im ersten Fall parst Qt die Zeichenkette gemäß der deutschen Spracheinstellung, im letzteren Fall gemäß den Regeln der POSIX-Lokalisierung.

Fehlerhaft platzierte Tausender-Trennzeichen werden in "QIntValidator.fixup()" wieder entfernt, damit die Eingabe als Zahl geparst werden kann. Anders ließe sich eine Eingabe von Zahlen mit Tausender-Trennzeichen innerhalb der Möglichkeiten von "QValidator" gar nicht umsetzen, da man von vorne herein nie sicher sein kann, ob nun noch Ziffer nach dem Trennzeichen eingegeben werden oder nicht. Du kannst zwar von "QIntValidator" ableiten und ".fixup()" überschreiben, musst dann aber auch ".validate()" so verändern, dass "Invalid" zurückgegeben wird, wenn das Tausender-Trennzeichen an falscher Stelle steht. Das ist nicht trivial.

Zumal Dein Quelltext ohnehin fehlerhaft ist, da Du "int()" verwendest, um die validierte Eingabe zu parsen. "int()" ignoriert die Spracheinstellungen der Umgebung, die validierte Eingabe ist aber abhängig von der Lokalisierung. Wenn Du "QIntValidator" verwendest, musst Du die Eingabe mit "QLocale" parsen.

In Deinem Fall bist Du allerdings wohl besser bedient mit einem eigenen, ziemlich trivialen "QValidator":

Code: Alles auswählen

class StrictIntValidator(QValidator):
    def __init__(self, min, max, parent=None):
        QValidator.__init__(self, parent)
        self.min = min
        self.max = max

    def validate(self, input, pos):
        try:
            value = int(input.strip())
            state = QValidator.Acceptable if self.min <= value <= self.max else QValidator.Invalid
            return state, input, pos
        except ValueError:
            return QValidator.Invalid

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 21:05
von noisefloor
Hallo,

@lunar: Ah, Danke für die Erklärung. Jetzt habe ich es auch verstanden. :-)

Wobei ich selber nie auf die Idee kommen würde, ein Zahl mit Tausender-Separatoren einzutippen - weder in Qt noch in Excel noch in ... aber egal, anderes Thema.

Gruß, noiselfoor

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Mittwoch 18. Januar 2012, 21:40
von Hyperion
@lunar: Doch ich habe die Doku schon durchgelesen - nur hatte ich keine zunächst keine Ahnung, was man mit diesen locale-Sachen alles anstellen kann. Und speziell die `fixup`-Methode ist eher schlecht dokumentiert! Durch BlackJacks Anmerkung ist mir dann schon klar geworden, dass sich die Trennzeichen nur an bestimmten Stellen stehen dürfen; dass `QIntValidator` die entsprechend rausnimmt, wenn eine gültige Zahl noch möglich wäre, war doch dann imho klar?

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Donnerstag 19. Januar 2012, 10:13
von Hyperion
@noisefloor: Ich habe gerade auf uu.de Deinen Blog-Eintrag gelesen. Mir fiel dabei auf, dass Du eine Variante mit `argparse` nicht aufgeführt hast. Meiner Meinung nach wäre das doch die simpelste Lösung vom Code her:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse

parser = argparse.ArgumentParser(u"Programm zum Quadrieren von Integerzahlen.")
parser.add_argument("value", type=int)

args = parser.parse_args()
print args.value * args.value
Nach Deiner Zählweise wären das fünf Zeilen Code - deutlich kürzer als das selbst gebaute Command Line Parsing ;-)

Ich habe bis vor kurzem bei simplen Scripten auch immer auf `argparse` verzichtet; lunar brachte mich mit einem Posting wieder in die "Spur" und zeigte, wie einfach dieses auf den ersten Blick abschreckende Modul sein kann :-)

(Zugegebener Maßen sind die Fehlermeldungen nicht auf deutsch und nicht exakt so, wie Du sie in Deinem Script hast)

Ist es eine bewusste Entscheidung, dass Du auf Syntaxhighlighting in Deinem Blog verzichtest? Ich würde doch dafür plädieren :-)

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Donnerstag 19. Januar 2012, 10:19
von lunar
Zumal sich Vergleich relativiert, wenn man die GUI im Designer erzeugt.

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Donnerstag 19. Januar 2012, 14:44
von noisefloor
Hallo,
Ist es eine bewusste Entscheidung, dass Du auf Syntaxhighlighting in Deinem Blog verzichtest? Ich würde doch dafür plädieren
Nein. Nur bin ich durch die Untiefen von eignenen Stylesheets etc. noch nicht durch gestiegen. Zumal das von Blogspot.com erzeugte HTML sehr... komisch ist.

Gruß. noisefloor

Re: merkwürdiges Verhaltn QIntValidator

Verfasst: Donnerstag 19. Januar 2012, 17:24
von nomnom
noisefloor hat geschrieben:Hallo,
Ist es eine bewusste Entscheidung, dass Du auf Syntaxhighlighting in Deinem Blog verzichtest? Ich würde doch dafür plädieren
Nein. Nur bin ich durch die Untiefen von eignenen Stylesheets etc. noch nicht durch gestiegen. Zumal das von Blogspot.com erzeugte HTML sehr... komisch ist.

Gruß. noisefloor
Bei „yacoding.blogspot.com“ wird zum Beispiel erklärt wie man das einrichten kann. ;) Als Hoster bieten sich zum Beispiel Dropbox oder ein Paste-Service (mit Unterstützung für das Anzeigen des „rohen“ Pastes) an. Wobei ich

Code: Alles auswählen

<script type="text/javascript" src="..."></script>
benutzen würde.