Entry: Eingaben prüfen, "," durch "." er

Fragen zu Tkinter.
Antworten
fatrat
User
Beiträge: 8
Registriert: Mittwoch 3. Dezember 2008, 11:03

Hallo,

habe folgendes Problem: ich möchte die eingegebenen Daten in einem Entry-Widget prüfen und ggf. ändern ("," mit "." ersetzen). Schritt 1: Mittels eines Re-Objekts prüfe ich die Eingabe; wenn da was anderes drinsteht außer Zahlen, Kommas oder Punkte, dann motzt das Programm (das funktioniert auch). Schritt 2: Komma durch Punkt ersetzen. Wie kann ich auf die "textvariable" des Widgets zugreifen (eine .set-Methode hat das Entry-Widget ja nicht)? Hab versucht, das "event.widget" über seinen Namen anzusprechen (.winfo_name()), aber das klappt nicht. Ich habe es auch mit den Methoden .getvar() und .setvar() probiert (http://effbot.org/tkinterbook/widget.ht ... var-method), aber mir ist nicht ganz klar, welche Variablen damit überhaupt gemeint sind. Irgendwo hab ich auch noch was von "validate"-Methoden gelesen, aber ich weiß nicht, ob die in Python 2.5 überhaupt eingebaut sind.

Schonmal Danke für evtl. Hinweise.

Code: Alles auswählen

from Tkinter import *
from re import *
import tkMessageBox


def pruefe(event):
    re_reinraus = compile("([1-9]\d+[.,]\d+$)|([1-9]\d+$|[0-9])")
    eingabe = event.widget.get()
    if not re_reinraus.match(eingabe):
        tkMessageBox.showwarning("Fehler","bitte eingabe pruefen")
        event.widget.focus_set()
        return
    # komma durch punkt ersetzen
    if "," in eingabe:
        print "Komma drin"
        variable = str(event.widget)
        widgetname = event.widget.winfo_name()
        print "Variable: ",variable
        a=eingabe.replace(",",".")
        variable.set(a)
    if eingabe.isdigit():
        event.widget.setvar(eingabe+".00")

fenster=Tk()

entry1_var = StringVar()
entry1 = Entry(fenster,textvariable=entry1_var)
entry1.bind("<FocusOut>",pruefe)
entry1.pack()
entry2 = Entry(fenster)
entry2.pack()



fenster.mainloop()
Birne94
User
Beiträge: 90
Registriert: Freitag 28. November 2008, 15:18
Kontaktdaten:

Code: Alles auswählen

entry1_var.set("foo")
oder verstehe ich dich jetzt nicht?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

fatrat hat geschrieben:habe folgendes Problem: ich möchte die eingegebenen Daten in einem Entry-Widget prüfen und ggf. ändern ("," mit "." ersetzen).
Die Vorgehensweise hängt davon, ob du die Prüfung/Änderung erst nach vollständiger Eingabe und dann z.B. per Buttonklick durchführen willst, oder "in time" schon während der Eingabe.

Im ersten Fall nimmst du einfach den ganzen Inhalt mit der get()-Methode heraus, ersetzt via string.replace() und schreibst das ganze mittels insert() wieder in das Entry-Feld hinein.

Im zweiten Fall müsstest du über Tastatur-Events gehen, und zwar entweder auf jeden Tastendruck bzw. das Loslassen reagieren oder nur auf das Komma.
Birne94
User
Beiträge: 90
Registriert: Freitag 28. November 2008, 15:18
Kontaktdaten:

Ich habe dazu auch mal eine Frage:
Wenn ich bei einem Text-/Entrywidget den Tastendruck "binde" (widget.bind("<Any-Key>",myfns)), wird das Callback vor oder nach dem Einfügen des Zeichens in das Textfeld aufgerufen
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Birne94 hat geschrieben:Ich habe dazu auch mal eine Frage:
Wenn ich bei einem Text-/Entrywidget den Tastendruck "binde" (widget.bind("<Any-Key>",myfns)), wird das Callback vor oder nach dem Einfügen des Zeichens in das Textfeld aufgerufen
Kommt darauf an, an welches Event du bindest. Für den Fall von fatrat müsste man KeyRelease nehmen. Sähe dann so aus:

Code: Alles auswählen

import Tkinter as tk
root = tk.Tk()
var = tk.StringVar()
entry = tk.Entry(root, textvariable=var)
entry.bind("<KeyRelease>", lambda e:var.set(var.get().replace(",",".")) )
entry.pack()
root.mainloop()
Im übrigen ist die Verwendung einer StringVar hier natürlich der "get() - delete() - insert()" - Variante vorzuziehen.
fatrat
User
Beiträge: 8
Registriert: Mittwoch 3. Dezember 2008, 11:03

@Birne, ich kenne ja den Namen der Textvariable zur Laufzeit nicht, da das Event ja an mehrere Widgets gebunden werden soll (sorry, hab ich nicht dazugesagt).

@numerix, ich benutze <FocusOut> als event. Schade, dass ich nicht direkt die Textvariable schreiben kann (da ich ihren Namen ja nicht kenne, s.o.), so muss ich wohl - wie du es vorgeschlagen hast - mit insert versuchen.

weißt du evtl. noch, was es mit den .setvar() und .getvar()-Methoden auf sich hat?

danke für eure Antworten!
Birne94
User
Beiträge: 90
Registriert: Freitag 28. November 2008, 15:18
Kontaktdaten:

mach doch folgendes:

Code: Alles auswählen

foo = Entry(root, textvarialbe=var)
foo.myvar = var
und dann später in dem Event-Handler:

Code: Alles auswählen

event.widget.myvar.set("blah")
ich glaube, dass es so geht. bin aba nicht sicher
Zuletzt geändert von Birne94 am Montag 9. Februar 2009, 17:06, insgesamt 1-mal geändert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

fatrat hat geschrieben:@numerix, ich benutze <FocusOut> als event. Schade, dass ich nicht direkt die Textvariable schreiben kann (da ich ihren Namen ja nicht kenne, s.o.), so muss ich wohl - wie du es vorgeschlagen hast - mit insert versuchen.
Ich sehe noch nicht, warum irgendein Fall über StringVar nicht funktionieren sollte, der über get - delete - insert funktioniert.

Wenn du das Problem genauer beschreibst bzw. entsprechenden Code zeigst, könnte man der Sache evtl. auf den Grund gehen.
fatrat
User
Beiträge: 8
Registriert: Mittwoch 3. Dezember 2008, 11:03

Hallo numerix,
du hast natürlich Recht - es funktioniert so, wie du es gesagt hast. Schonmal vielen Dank für den Hinweis!

Du hast aber auch geschrieben:
Im übrigen ist die Verwendung einer StringVar hier natürlich der "get() - delete() - insert()" - Variante vorzuziehen.
das sehe ich eben auch so, und dachte, ich könnte via .setvar() die Textvariable schreiben, auch unbekannterweise. Hier der Code:

Code: Alles auswählen

from Tkinter import *
from re import *
import tkMessageBox


def pruefe(event):
    re_reinraus = compile("([1-9]\d+[.,]\d+$)|([1-9]\d+$|[0-9])")
    eingabe = event.widget.get()
    if not re_reinraus.match(eingabe):
        tkMessageBox.showwarning("Fehler","bitte eingabe pruefen")
        event.widget.focus_set()
        return
    # komma durch punkt ersetzen
    if "," in eingabe:
        # hier weiss ich ja nicht, wie die Textvariable des Widgets heisst, denn es koennte
        # eines von mehreren Widges sein, das den event ausloest (s.u. - entry1_var oder entry2_var)
        a=eingabe.replace(",",".")
        event.widget.setvar(a) # <--- das funzt leider nicht
        # das hier funktioniert, aber eben ohne das Textvariablen-Objekt:
        event.widget.delete(0,END)
        event.widget.insert(0,a)

fenster=Tk()
# Entry-Widget 1
entry1_var = StringVar()
entry1 = Entry(fenster,textvariable=entry1_var)
entry1.bind("<FocusOut>",pruefe)
entry1.pack()
# Entry-Widget 2
entry2_var = StringVar()
entry2 = Entry(fenster,textvariable=entry2_var)
entry2.bind("<FocusOut>",pruefe)
entry2.pack()

fenster.mainloop()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Es geht schon mit StringVars, aber dann muss der Ansatz anders sein.
So z.B.:

Code: Alles auswählen

import Tkinter as tk
import tkMessageBox 

def pruefe(e): 
    inhalt = entryvars[e.widget].get()
    for z in inhalt:
        if not z in "01234567890,.":
            tkMessageBox.showwarning("Fehler", "Eingabe pruefen")
            return
    entryvars[e.widget].set(inhalt.replace(",","."))
    
fenster = tk.Tk() 
entryvars = {}
for n in range(10):
    entryvars[tk.Entry(fenster)] = tk.StringVar()
for entry in entryvars:
    entry["textvariable"] = entryvars[entry]
    entry.bind("<FocusOut>", pruefe)
    entry.pack()
fenster.mainloop()
Die Tabulatorreihenfolge der Entry-Widgets ist jetzt ungeordnet wg. des Dictionaries. Falls du es so machen willst, könntest du zunächst eine Liste von Entry-Widgets erstellen und damit dann das Dictionary befüllen.
Antworten