Supongamos que tengo lo siguiente Button
hecho con Tkinter en Python:
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)
Se action
llama al método cuando presiono el botón, pero ¿y si quisiera pasar algunos argumentos al método action
?
He intentado con el siguiente código:
button = Tk.Button(master=frame, text='press', command=action(someNumber))
Esto solo invoca el método inmediatamente, y presionar el botón no hace nada.
Respuestas:
Personalmente prefiero usarlo
lambdas
en tal escenario, porque en mi opinión es más claro y simple y tampoco te obliga a escribir muchos métodos de envoltura si no tienes control sobre el método llamado, pero eso es ciertamente una cuestión de gustos.Así es como lo haría con un lambda (tenga en cuenta que también hay alguna implementación de curry en el módulo funcional, por lo que también puede usar eso):
fuente
partial
funciona en este caso."This just invokes the method immediately, and pressing the button does nothing"
sucede la declaración de OP ?callback=lambda x=x: f(x)
como enfs = [lambda x=x: x*2 for x in range(5)] ; print [f() for f in fs]
Esto también se puede hacer mediante el uso
partial
de functools de biblioteca estándar , como este:fuente
button = Tk.Button(master=frame, text='press', command=partial(action, arg))
action_with_args = partial(action, arg1, arg2... argN)
GUI de ejemplo:
Digamos que tengo la GUI:
¿Qué sucede cuando se presiona un botón?
Observe que cuando
btn
se presiona llama a su propia función, que es muy similar abutton_press_handle
la del siguiente ejemplo:con:
Simplemente puede pensar que esa
command
opción debe establecerse como, la referencia al método que queremos llamar, similar acallback
inbutton_press_handle
.Llamar a un método ( devolución de llamada ) cuando se presiona el botón
Sin argumentos
Entonces, si quería
print
algo cuando se presiona el botón, necesitaría configurar:Preste mucha atención a la falta de
()
unprint
método que se omite en el sentido de que: "Este es el nombre del método al que quiero que llame cuando lo presione, pero no lo llame en este mismo instante". Sin embargo, no pasé ningún argumento para el,print
por lo que imprimió lo que imprime cuando se lo llamó sin argumentos.Con argumento (s)
Ahora, si también quisiera pasar argumentos al método que quiero que me llamen cuando se presiona el botón, podría hacer uso de las funciones anónimas, que se pueden crear con la declaración lambda , en este caso para el
print
método incorporado, como el siguiente :Llamar a varios métodos cuando se presiona el botón
Sin argumentos
También puede lograrlo usando la
lambda
declaración, pero se considera una mala práctica y, por lo tanto, no la incluiré aquí. La buena práctica es definir un método separadomultiple_methods
que llame a los métodos deseados y luego configurarlo como la devolución de llamada al presionar el botón:Con argumento (s)
Para pasar argumentos al método que llama a otros métodos, nuevamente use la
lambda
declaración, pero primero:y luego establecer:
Devolver objeto (s) de la devolución de llamada
También tenga en cuenta que
callback
no puede realmentereturn
porque solo se llama dentrobutton_press_handle
concallback()
en lugar dereturn callback()
. Lo hace,return
pero no en cualquier lugar fuera de esa función. Por lo tanto, debería modificar los objetos a los que se puede acceder en el ámbito actual.Ejemplo completo con modificaciones de objeto globales
El siguiente ejemplo llamará a un método que cambia
btn
el texto de cada vez que se presiona el botón:Espejo
fuente
La capacidad de Python para proporcionar valores predeterminados para argumentos de función nos da una salida.
Ver: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/extra-args.html
Para más botones, puede crear una función que devuelva una función:
fuente
myX
ymyY
funciona perfectamente muchas gracias.Sobre la base de la respuesta de Matt Thompson: una clase se puede hacer invocable para que se pueda usar en lugar de una función:
fuente
La razón por la que invoca el método inmediatamente y al presionar el botón no hace nada es que
action(somenumber)
se evalúa y su valor de retorno se atribuye como el comando para el botón. Entonces, siaction
imprime algo para decirle que se ha ejecutado y regresaNone
, solo ejecutaaction
para evaluar su valor de retorno y se le daNone
como el comando para el botón.Para tener botones para llamar a funciones con diferentes argumentos, puede usar variables globales, aunque no puedo recomendarlo:
Lo que haría es hacer un
class
objeto cuyos objetos contendrían todas las variables requeridas y métodos para cambiarlos según sea necesario:fuente
Creo que debería arreglar esto
fuente
Lo mejor que puede hacer es usar lambda de la siguiente manera:
fuente
Llego extremadamente tarde, pero aquí hay una manera muy simple de lograrlo.
Simplemente envuelva la función que desea usar en otra función y llame a la segunda función al presionar el botón.
fuente
var1
yvar2
en el módulo principal, puede omitirfunction1
y poner unaprint
declaraciónfunction2
. ¿Se refiere a otras situaciones que no entiendo?Las lambdas están muy bien, pero también puedes probar esto (que funciona en un bucle for por cierto):
Esto funciona porque cuando se establece el enlace, una pulsación de tecla pasa el evento como argumento. A continuación, puede llamar los atributos fuera del evento como
event.char
obtener "1" o "UP" ect. Si necesita un argumento o varios argumentos distintos de los atributos del evento. solo crea un diccionario para almacenarlos.fuente
También he encontrado este problema antes. Puedes usar lambda:
fuente
Use una lambda para pasar los datos de entrada a la función de comando si tiene más acciones para llevar a cabo, de esta manera (he intentado hacerlo genérico, así que solo adapte):
Esto pasará la información en el evento a la función del botón. Puede haber más formas pitonescas de escribir esto, pero funciona para mí.
fuente
JasonPy - algunas cosas ...
Si coloca un botón en un bucle, se creará una y otra vez ... lo que probablemente no sea lo que desea. (tal vez lo es) ...
La razón por la que siempre obtiene el último índice son los eventos lambda que se ejecutan cuando hace clic en ellos, no cuando se inicia el programa. No estoy seguro al 100% de lo que está haciendo, pero tal vez intente almacenar el valor cuando esté hecho y luego llámelo más tarde con el botón lambda.
por ejemplo: (no use este código, solo un ejemplo)
entonces puedes decir ...
¡espero que esto ayude!
fuente
Una forma sencilla sería configurar
button
conlambda
la siguiente sintaxis:fuente
Para la posteridad: también puedes usar clases para lograr algo similar. Por ejemplo:
El botón puede ser creado simplemente por:
Este enfoque también le permite cambiar los argumentos de la función, es decir, estableciendo
instance1.x = 3
.fuente
Necesitas usar
lambda:
fuente
Utilizar lambda
salida:
fuente