Knopf-Event

Fragen zu Tkinter.
Antworten
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Hallo!
Ich möchte mir gerade ein GUI für meine Caesar-Verschlüsselung basteln. Aber immer wenn ich diese starte, kommt das ``tkMessageBox.showinfo()``-Fenster, und bei Klick auf den »Encrypt«-Knopf passiert nichts. Woran liegt das? Wo liegt mein doofer Denkfehler? ;)

Code: Alles auswählen

#!/usr/bin/env python
import caesar
import Tkinter
import ScrolledText
import tkMessageBox

class Application(Tkinter.Frame):
    def create_widgets(self):
        self.shift_input = Tkinter.Entry(self)
        self.shift_input.pack()
        self.shift_content = Tkinter.StringVar()
        self.shift_input['textvariable'] = self.shift_content

        self.textfield = ScrolledText.ScrolledText(self)
        self.textfield.pack()

        self.encrypt_button = Tkinter.Button(self, text='Encrypt')
        self.encrypt_button['command'] = tkMessageBox.showinfo('Shift', self.shift_content.get())
        self.encrypt_button.pack({"side": "left"})

        self.decrypt_button = Tkinter.Button(self, text='Decrypt')
        self.decrypt_button.pack({"side": "left"})

        self.quit_button = Tkinter.Button(self, text='Quit')
        self.quit_button['command'] = self.quit
        self.quit_button.pack({"side": "right"})

    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master)
        self.pack()
        self.create_widgets()

root = Tkinter.Tk()
app = Application(master=root)
app.mainloop()
root.destroy()
Ist natürlich noch nicht fertig. Mein Problem liegt bei dem hier:

Code: Alles auswählen

        self.encrypt_button['command'] = tkMessageBox.showinfo('Shift', self.shift_content.get())
Sollte diese Box dann nicht erst bei Klick auf »Encrypt« erscheinen? (Ich weiß, »Encrypt« passt zu dem was ich tun will nicht, aber es geht nur darum, um zu sehen wie es funktioniert)

Bei dem funktioniert es ja:

Code: Alles auswählen

        self.quit_button['command'] = self.quit
Viele Grüße,
Jakob.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Erstens bitte auf optionale Parameter wie "command" in Tkinter mit .config(command=...) ändern.
Zweitens du rufst das Fenster sofort auf, du brauchst aber ein "callback", also nutze ein lambda.

Code: Alles auswählen

        func = lambda: tkMessageBox.showinfo('Shift', self.shift_content.get())
        self.encrypt_button.config(command=func)
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Xynon1 hat geschrieben:Erstens bitte auf optionale Parameter wie "command" in Tkinter mit .config(command=...) ändern.
Zweitens du rufst das Fenster sofort auf, du brauchst aber ein "callback", also nutze ein lambda.

Code: Alles auswählen

        func = lambda: tkMessageBox.showinfo('Shift', self.shift_content.get())
        self.encrypt_button.config(command=func)
Danke Xynon1 :-)
Ich dachte es wäre egal, ob man da eine Funktion oder eine nicht-Funktion als Argument angibt. So funktioniert es natürlich super.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

nomnom hat geschrieben:Ich dachte es wäre egal, ob man da eine Funktion oder eine nicht-Funktion als Argument angibt. So funktioniert es natürlich super.
Nein, ist es nicht, nochmal damit du auch wirklich den Hintergrund erfasst, wird dir in Tkinter wie sicherlich in anderen GUIs häufig über den Weg laufen.

Wenn du hinter eine Funktion Klammerst, also (), dann wird die Funktion gerufen.
Das ist nicht wirklich sinnvoll wenn sie bei einer Zuweisung, in welcher die Funktion beim Auslösen gerufen werden soll, schon ausgeführt wird. So bekommt dein "command" nämlich nur den return der Funktion, also bei

Code: Alles auswählen

>>> def a():
...        return 1
>>> b = a()
>>> b
1
>>> # Du brauchst aber die Funktion, also
>>> b = a
>>> b
<function a at 0x89c6fb4>
So wird einfach nur der "callback" der Funktion an "b" gegeben, was zur folge hat das du "b" jetzt mit Klammern rufen kannst.
Wie du vieleicht bemerkt hast macht sich das bei Parametern etwas schwerer, dafür gibt es dann das Keyword "lambda".
Dieses sorgt dafür das eine Funktion zurück gegeben wird.
Folgendes ist zB im prinzip das gleiche:

Code: Alles auswählen

>>> def a(x):
...	    return x * x
>>> a(2)
4
>>> # oder
>>> b = lambda x: x * x
>>> b(2)
4
Und in deinem Script oben machst du nun nichst weiter als

Code: Alles auswählen

>>> c = lambda: a(2)
>>> c()
4
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Vielen vielen Dank, Xynon1. :D
Du hast dir da wirklich viel Mühe gegeben, und habs jetzt verstanden. Ist eigentlich logisch, aber beim Programmieren fällt mir sowas gar nicht auf. :|
Viele Grüße,
Jakob.
Antworten