Inhalt von Entry-Widget löschen

Fragen zu Tkinter.
Antworten
tomkin
User
Beiträge: 12
Registriert: Sonntag 10. April 2011, 11:23

Ich möchte über ein Eingabefeld Ziffern eingeben lassen, diese werden danach verarbeitet, und anschließend soll der Inhalt des Felder wieder gelöscht werden. Dann kann die nächste Eingabe erfolgen.

Hier die dafür verwendeten Programmteile:

Code: Alles auswählen

def auswaehlen(eingabe):
    # Zuvor Eingabe verarbeiten, dann Inhalt des Eingabefelds für nächste Eingabe löschen
    eing.delete()

eing = tkinter.Entry(frame2,width=2,font="arial 11 bold")
eing.bind("1",auswaehlen)
eing.bind("3",auswaehlen)
eing.bind("2",auswaehlen)
eing.place(x=90,y=100)
Ergebnis:
Ich kann eingeben, jede Eingabe wird richtig verarbeitet, aber die Ziffer wird nicht wieder gelöscht. Es wird immer die neue Eingabe an die alte angefügt.

Fehlermeldung: "TypeError: delete() takes at least 2 positional arguments (1 given)"

Wenn ich in der Funktion

Code: Alles auswählen

    eing.delete(0,1)
schreibe, dann kommt keine Fehlermeldung. Es wird aber auch nichts gelöscht.

Was mache ich falsch?
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Im Prinzip 3 Sachen:
1. "eing" ist bei dir auf Modulebene definiert und du greifst in der Funktion darauf zu, das ist nicht sehr schön.
2. Deine Eingabe ist ein Ereignis und keine Widget. Aber ein Ereignis hat ein "widget"-Attribute auf das man zugreifen kann und die Eingabe kann man über das "keysym"-Attribute erhalten.

Also so hier:

Code: Alles auswählen

import Tkinter as tkinter

def _input(event):
    print event.keysym
    event.widget.delete(0, "end")

if __name__ == "__main__":
    root = tkinter.Tk()

    entry = tkinter.Entry(root)
    entry.bind("1", _input)
    entry.bind("2", _input)
    entry.bind("3", _input)
    entry.pack(fill="x")
    
    root.mainloop()
3. Das wichtigste aber ist, das ein Event vor dem Eintrag der Zahl in das Widget ausgelöst wird und damit immer nur der vorherige Inhalt gelöscht werden kann. Möchtest du dennoch das Feld nach der Eingabe löschen, müsstest du die "delete"-Funktion wohl mit einer "after"-Methode aufrufen müssen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
tomkin
User
Beiträge: 12
Registriert: Sonntag 10. April 2011, 11:23

Vielen Dank! Genau so soll's funktionieren. Die letzte Eingabe soll solange im Eingabefeld stehen bleiben, bis die neue kommt, und das tut's. Danke nochmal!
tomkin
User
Beiträge: 12
Registriert: Sonntag 10. April 2011, 11:23

Hm.. das nächste Problem. Sorry, ich bin noch Python-Anfänger :oops:

Wenn ich nun die Eingabe mit

Code: Alles auswählen

eingabe = event.keysym
in eine Variable speichere, wie kann ich das Programm dann auf die ESC-Taste und die Pfeiltasten reagieren lassen.

Code: Alles auswählen

if eingabe == chr(27):
beispielsweise für die Escape-Taste funktioniert leider nicht.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ist ja auch Blödsinn :D, wir arbeiten hier mit etwas modeneren Mitteln (20+ Jahre alt).
Spaß bei Seite, du bekommst bei Escape eine String bei keysym und zwar taadaa "Escape". Ich vermute mal du mal du hast den Auslöser nicht richtig gesetzt, müsste so hier gehen

Code: Alles auswählen

entry.bind("<Escape>", _input)
Eine Übersticht über die Events kannst du dir hier verschaffen: http://effbot.org/tkinterbook/tkinter-e ... ndings.htm
Wenn du aber lieber mit der 27 arbeitest, dann musst du "keycode" statt keysym nehmen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
tomkin
User
Beiträge: 12
Registriert: Sonntag 10. April 2011, 11:23

Wow, es ist alles viel einfacher als ich dachte!

Code: Alles auswählen

if eingabe == "Left"
zum Beispiel für die linke Pfeiltaste.

Ich liebe Python jetzt schon!
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Das hat allerdings nicht viel mit Python zutun, sonder mit Tk. Aber mit Python ist Tk wesentlich schöner zu handhaben als mit tcl oder perl.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
tomkin
User
Beiträge: 12
Registriert: Sonntag 10. April 2011, 11:23

Hm.. weiter geht's mit meinen Fragen :oops:

Ich gebe nun eine Ziffer ein, mit der das Programm arbeitet.
Von da an werden bis zur Eingabe von <Escape> nur mehr Eingaben über die Pfeiltasten oder eben <Escape> erwartet.

Das Problem ist nun folgendes:
Wenn ich nun trotzdem etwas anderes eingebe, soll das sofort wieder aus dem Widget gelöscht werden und die Ziffer der ersten Eingabe dort stehen bleiben. Mit

Code: Alles auswählen

event.widget.delete(0,"end")
bleibt immer die aktuelle Eingabe im Feld. Ich dachte eigentlich,

Code: Alles auswählen

event.widget.delete(1,"end")
würde funktionieren und die letzte Eingabe wieder löschen, tut es aber nicht. Ist das ein Fall, wo ich diese after-Methode (von der ich natürlich keine blassen Schimmer habe, was die tut und wie sie funktioniert) verwenden muss?

Und das nächste Problem:

Code: Alles auswählen

eing.bind("1",ersteauswahl)
eing.bind("2",ersteauswahl)
eing.bind("3",ersteauswahl)
eing.bind("4",ersteauswahl)
eing.bind("5",ersteauswahl)
eing.bind("6",ersteauswahl)
eing.bind("7",ersteauswahl)
eing.bind("8",ersteauswahl)
eing.bind("9",ersteauswahl)
eing.bind("<Escape>",escape)
Left, Right, Up und Down werden auch noch Funktionen auslösen.
Alle anderen Eingaben sollen dann die gleiche Funktion (wieder eine zum Löschen der Neueingabe) auslösen. Aber wie mache ich eing.bind für "alle anderen"?
BlackJack

"Für alle anderen" wird wohl nicht gehen, wohl aber "für alle". Das ist im ersten Beispiel auf der verlinkten `Tkinter`-Seite von Effbot zu sehen. Und was `after()` macht, kann man da auch irgendwo nachlesen.

Edit: Für alle anderen geht doch. Einfach mal die Seite dort durchlesen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@BlackJack
Jetzt habe ich mir schon solche Mühe gemacht :arrow:

Das könnte man so realisieren:

Code: Alles auswählen

def delete(widget):
    widget.delete(1, "end")
    
def _input(event):
    widget = event.widget 
    if event.keysym in "0123456789":
        widget.delete(0, "end")
    elif event.keysym == "Escape":
        pass
    else:
        widget.after(10, delete, widget)
    
if __name__ == "__main__":
    root = tkinter.Tk()

    entry = tkinter.Entry(root)
    entry.bind("<Key>", _input)
    entry.pack(fill="x")
   
    root.mainloop()
Also bindet alle Key-Events an das Entry und entscheidet dann in der Funktion wie diese behandelt werden. Wird eine Zahl von 0-9 gewählt, so soll alles vorherige gelöscht werden. Wenn anderer Tasten gedrückt werden, wird auch irgendwas gemacht. Und sollte die Taste nicht definiert sein so wird alles hinter der Zahl mit der "after"-Methode gelöscht. Nochmmal zur Erinnerung die "after"-Methode ist hier nicht sehr schön, da sie Zeit gesteuert ist. Jedes Widget hat diese Methode, kann also von jedem genutzt werden. Die Wirkung ist einfach nur das eine Funktion nach einer bestimmten Zeit, 1. Parameter in Millisekunden, gerufen wird. Der 2. Parameter ist dann die Funktion und der 3., 4., ... die Paramter die an die Funktion übermittelt werden sollen. Hier nochmal zum nachlesen: http://effbot.org/tkinterbook/widget.ht ... ter-method

Eventuell wäre ein Label für diese Art besser geeignet, dem könnte man vorschreiben, was es anzeigen soll und was nicht. Und nicht unerwünchtes hintenherum wieder löschen. Das könnte dann in etwa so aussehen:

Code: Alles auswählen

def _input(event):
    if event.keysym in "123456789":
        event.widget.config(text=event.keysym)
    elif event.keysym == "Escape":
        pass
    
if __name__ == "__main__":
    root = tkinter.Tk()

    label = tkinter.Label(root, width=30, takefocus=True)
    label.bind("<Key>", _input)
    label.pack(fill="x")
    label.focus_set()
   
    root.mainloop()
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: So könnte man es natürlich auch machen.
Antworten