Angenommen, ich habe die folgende Button
mit Tkinter in Python erstellt:
import Tkinter as Tk
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=1, column=1)
button = Tk.Button(master=frame, text='press', command=action)
Die Methode action
wird aufgerufen, wenn ich die Taste drücke. Was aber, wenn ich einige Argumente an die Methode action
übergeben wollte?
Ich habe folgenden Code ausprobiert:
button = Tk.Button(master=frame, text='press', command=action(someNumber))
Das ruft die Methode einfach sofort auf und das Drücken der Taste bewirkt nichts.
Ich persönlich ziehe es vor, lambdas
in einem solchen Szenario zu verwenden, denn imo ist es klarer und einfacher und zwingt Sie auch nicht dazu, viele Wrapper-Methoden zu schreiben, wenn Sie die aufgerufene Methode nicht steuern können. Dies ist jedoch eine Frage des Geschmacks.
So machen Sie es mit einem Lambda (beachten Sie, dass auch das Currying im Funktionsmodul implementiert ist, sodass Sie das auch verwenden können):
button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))
Dies kann auch durch Verwendung von partial
aus der Standardbibliothek functools wie folgt durchgeführt werden:
from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)
Pythons Fähigkeit, Standardwerte für Funktionsargumente bereitzustellen, gibt uns einen Ausweg.
def fce(x=myX, y=myY):
myFunction(x,y)
button = Tk.Button(mainWin, text='press', command=fce)
Siehe: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/extra-args.html
Für weitere Schaltflächen können Sie eine Funktion erstellen, die eine Funktion zurückgibt:
def fce(myX, myY):
def wrapper(x=myX, y=myY):
pass
pass
pass
return x+y
return wrapper
button1 = Tk.Button(mainWin, text='press 1', command=fce(1,2))
button2 = Tk.Button(mainWin, text='press 2', command=fce(3,4))
button3 = Tk.Button(mainWin, text='press 3', command=fce(9,8))
Nehmen wir an, ich habe die GUI:
import tkinter as tk
root = tk.Tk()
btn = tk.Button(root, text="Press")
btn.pack()
root.mainloop()
Wenn Sie btn
drücken, ruft es seine eigene Funktion auf, die button_press_handle
im folgenden Beispiel sehr ähnlich ist:
def button_press_handle(callback=None):
if callback:
callback() # Where exactly the method assigned to btn['command'] is being callled
mit:
button_press_handle(btn['command'])
Sie können einfach denken, dass die Option command
als Referenz auf die Methode festgelegt werden soll, die aufgerufen werden soll, ähnlich wie callback
in button_press_handle
.
Ohne Argumente
Wenn ich also etwas print
wollte, wenn die Taste gedrückt wird, müsste ich Folgendes einstellen:
btn['command'] = print # default to print is new line
Achten Sie genau auf das lack von ()
mit der print
-Methode, die in der Bedeutung weggelassen wird: "Dies ist der Name der Methode, die Sie mit aufrufen möchten, aber nicht aufrufen genau diesen Augenblick. " Allerdings habe ich keine Argumente für die print
übergeben, sodass das gedruckt wurde, wenn es ohne Argumente aufgerufen wird.
Mit Argument (en)
Wenn ich nun auch Argumente an the method übergeben wollte, möchte ich beim Drücken des Buttons aufgerufen werden, ich könnte die anonymen Funktionen verwenden, die mit lambda in diesem Fall erstellt werden können print
integrierte Methode wie die folgende:
btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)
Ohne Argumente
Sie können dies auch mit der lambda
-Anweisung erreichen, aber es wird als schlechte Praxis betrachtet, und deshalb werde ich es hier nicht einschließen. Es empfiehlt sich, eine separate Methode, multiple_methods
, zu definieren, die die gewünschten Methoden aufruft, und diese dann als Rückruf für den Tastendruck festzulegen:
def multiple_methods():
print("Vicariously") # the first inner callback
print("I") # another inner callback
Mit Argument (en)
Um Argumente an Methoden zu übergeben, die andere Methoden aufrufen, verwenden Sie erneut die Anweisung lambda
.
def multiple_methods(*args, **kwargs):
print(args[0]) # the first inner callback
print(kwargs['opt1']) # another inner callback
und dann einstellen:
btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)
Beachten Sie außerdem, dass callback
nicht wirklich return
kann, da sie nur in button_press_handle
mit callback()
im Gegensatz zu return callback()
aufgerufen wird. Es macht return
, aber nicht irgendwo außerhalb dieser Funktion. Daher sollten Sie eher Objekte ändern, auf die im aktuellen Bereich zugegriffen werden kann.
Im folgenden Beispiel wird eine Methode aufgerufen, die den Text von btn
bei jedem Tastendruck ändert:
import tkinter as tk
i = 0
def text_mod():
global i, btn # btn can be omitted but not sure if should be
txt = ("Vicariously", "I", "live", "as", "the", "whole", "world", "dies")
btn['text'] = txt[i] # the global object that is modified
i = (i + 1) % len(txt) # another global object that gets modified
root = tk.Tk()
btn = tk.Button(root, text="My Button")
btn['command'] = text_mod
btn.pack(fill='both', expand=True)
root.mainloop()
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))
Ich glaube, ich sollte das beheben
Eine einfache Möglichkeit wäre, button
mit lambda
wie folgt zu konfigurieren:
button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)
Der Grund, warum die Methode sofort aufgerufen wird, und das Drücken der Schaltfläche bewirkt nichts, da action(somenumber)
ausgewertet wird und ihr Rückgabewert als Befehl für die Schaltfläche zugewiesen wird. Wenn also action
etwas ausgibt, um anzuzeigen, dass es ausgeführt wurde, und None
zurückgibt, führen Sie einfach action
aus, um den Rückgabewert auszuwerten, und geben None
als Befehl für die Schaltfläche an.
Um Schaltflächen zum Aufrufen von Funktionen mit verschiedenen Argumenten zu haben, können Sie globale Variablen verwenden, obwohl ich sie nicht empfehlen kann:
import Tkinter as Tk
frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN)
frame.grid(row=2,column=2)
frame.pack(fill=Tk.X, padx=5, pady=5)
def action():
global output
global variable
output.insert(Tk.END,variable.get())
button = Tk.Button(master=frame, text='press', command=action)
button.pack()
variable = Tk.Entry(master=frame)
variable.pack()
output = Tk.Text(master=frame)
output.pack()
if __== '__main__':
Tk.mainloop()
Was ich tun würde, ist eine class
, deren Objekte jede benötigte Variable und Methoden enthalten würden, um diese nach Bedarf zu ändern:
import Tkinter as Tk
class Window:
def __init__(self):
self.frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN)
self.frame.grid(row=2,column=2)
self.frame.pack(fill=Tk.X, padx=5, pady=5)
self.button = Tk.Button(master=self.frame, text='press', command=self.action)
self.button.pack()
self.variable = Tk.Entry(master=self.frame)
self.variable.pack()
self.output = Tk.Text(master=self.frame)
self.output.pack()
def action(self):
self.output.insert(Tk.END,self.variable.get())
if __== '__main__':
window = Window()
Tk.mainloop()
Ich bin sehr spät dran, aber hier ist ein sehr einfacher Weg, dies zu erreichen.
import tkinter as tk
def function1(param1, param2):
print(str(param1) + str(param2))
var1 = "Hello "
var2 = "World!"
def function2():
function1(var1, var2)
root = tk.Tk()
myButton = tk.Button(root, text="Button", command=function2)
root.mainloop()
Sie wickeln einfach die Funktion, die Sie verwenden möchten, in eine andere Funktion ein und rufen die zweite Funktion auf, wenn Sie die Taste drücken.
JasonPy - ein paar Dinge ...
wenn Sie einen Button in eine Schleife stecken, wird er immer wieder erstellt ... was wahrscheinlich nicht das ist, was Sie wollen. (vielleicht ist es)...
Der Grund, warum immer der letzte Index angezeigt wird, ist das Ausführen von Lambda-Ereignissen, wenn Sie auf sie klicken, und nicht, wenn das Programm startet. Ich bin nicht ganz sicher, was Sie tun, aber versuchen Sie, den Wert zu speichern, wenn Sie ihn gemacht haben, und rufen Sie ihn später mit der Lambda-Taste auf.
zB: (Verwenden Sie diesen Code nicht, nur ein Beispiel)
for entry in stuff_that_is_happening:
value_store[entry] = stuff_that_is_happening
dann kannst du sagen ....
button... command: lambda: value_store[1]
hoffe das hilft!
Am besten verwenden Sie Lambda wie folgt:
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))
Für die Nachwelt: Sie können auch Klassen verwenden, um etwas Ähnliches zu erreichen. Zum Beispiel:
class Function_Wrapper():
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z
def func(self):
return self.x + self.y + self.z # execute function
Der Button kann dann einfach erstellt werden durch:
instance1 = Function_Wrapper(x, y, z)
button1 = Button(master, text = "press", command = instance1.func)
Mit diesem Ansatz können Sie auch die Funktionsargumente ändern, indem Sie instance1.x = 3
einstellen.
Verwenden Sie ein Lambda, um die Eingabedaten an die Befehlsfunktion zu übergeben, wenn Sie weitere Aktionen ausführen möchten (z. B. hier).
event1 = Entry(master)
button1 = Button(master, text="OK", command=lambda: test_event(event1.get()))
def test_event(event_text):
if not event_text:
print("Nothing entered")
else:
print(str(event_text))
# do stuff
Dadurch werden die Informationen im Ereignis an die Tastenfunktion weitergegeben. Es mag mehr pythoneske Schreibweisen geben, aber es funktioniert für mich.
Aufbauend auf der Antwort von Matt Thompsons: Eine Klasse kann aufrufbar gemacht werden, sodass sie statt einer Funktion verwendet werden kann
import tkinter as tk
class Callback:
def __init__(self, func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargs
def __call__(self):
self.func(*self.args, **self.kwargs)
def default_callback(t):
print("Button '{}' pressed.".format(t))
root = tk.Tk()
buttons = ["A", "B", "C"]
for i, b in enumerate(buttons):
tk.Button(root, text=b, command=Callback(default_callback, b)).grid(row=i, column=0)
tk.mainloop()