it-swarm.com.de

Wie übergeben Sie Argumente an einen Button-Befehl in Tkinter?

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.

115
Jack

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))
184
Voo

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)
54
Dologan

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))
8
MarrekNožka

Beispiel GUI:

Nehmen wir an, ich habe die GUI:

import tkinter as tk

root = tk.Tk()

btn = tk.Button(root, text="Press")
btn.pack()

root.mainloop()

Was passiert, wenn eine Taste gedrückt wird

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.


Aufrufen einer Methode ( Rückruf ) Wenn die Taste gedrückt wird

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)

Aufruf von Multiple -Methoden beim Drücken der Taste

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)

Rückgabe von Objekten aus dem Rückruf

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.


Vollständiges Beispiel mit global Objektänderung (en)

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()

Spiegel

6
Nae
button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))

Ich glaube, ich sollte das beheben

1
Harrison Sills

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)
1
Nae

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()
1
berna1111

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.

0
Rhett

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! 

0
David W. Beck

Am besten verwenden Sie Lambda wie folgt:

button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))
0
dominic thorpe

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.

0
Matt Thompson

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.

0
Jayce

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()
0