2012-06-02 31 views
18

Estoy intentando crear botones en tkinter dentro de un bucle for. Y con cada ciclo, pase el valor de conteo como un argumento en el valor de comando. Entonces, cuando se llama a la función desde el valor del comando, puedo decir qué botón se presionó y actuar en consecuencia. El problema es, digamos que len es 3, creará 3 botones con los títulos "Juego 1" hasta "Juego 3", pero cuando se presiona cualquiera de los botones, el valor impreso es siempre 2, la última iteración. Entonces parece que los botones se están haciendo como entidades separadas, pero el valor de i en los argumentos del comando parece ser el mismo. Aquí está el código:Botones de creación de tkinter de Python para argumentos de comando de paso de bucle

def createGameURLs(self): 
    self.button = [] 
    for i in range(3): 
     self.button.append(Button(self, text='Game '+str(i+1),command=lambda:self.open_this(i))) 
     self.button[i].grid(column=4, row=i+1, sticky=W) 
def open_this(self, myNum): 
    print(myNum) 

¿Hay una manera de obtener el valor de la corriente i, en cada iteración, a seguir con ese botón en particular? Gracias de antemano.

+0

Muchas gracias a los dos LukaD y BrenBarn, he estado luchando con eso durante varios días, créanlo o no. Ambas formas funcionaron perfectamente. Fui con el i = i fix por ahora, pero definitivamente voy a leer sobre los functools. Agradezco ambas respuestas. – Marcel

+0

Si la solución BrenBarns funciona para usted, entonces debe marcarla como su respuesta aceptada. – lukad

+0

posible duplicado de [pasar el argumento en el comando de botón Tkinter de python] (http://stackoverflow.com/questions/6920302/passing-argument-in-python-tkinter-button-command) –

Respuesta

6

Así es como funcionan los cierres en python. Me encontré con este problema una vez. Puede usar functools.partial para esto.

for i in range(3): 
    self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i))) 
34

Cambiar la lambda para lambda i=i: self.open_this(i).

Esto puede parecer mágico, pero esto es lo que está sucediendo. Cuando utiliza esa lambda para definir su función, la llamada a open_this no obtiene el valor de la variable i en el momento de definir la función. En cambio, realiza un cierre, que es una especie de nota que dice: "Debería buscar cuál es el valor de la variable i en en el momento en que me llamo". Por supuesto, la función se llama después de que el ciclo ha terminado, por lo que en ese momento siempre será igual al último valor del ciclo.

El truco i=i hace que su función almacene el valor actual de i en el momento en que se define su lambda, en lugar de esperar a buscar el valor de i más tarde.

+0

¿Qué pasaría si quisiéramos pasar dos argumentos a una función como open_this? – Amen

+1

@Amen: Depende de lo que quiera que sean esos argumentos. Si ambos provienen de un bucle externo y quieres "congelarlos" de la forma que se muestra arriba, simplemente harías 'lambda x = x, y = y: self.open_this (x, y)'. – BrenBarn

+0

Esta es una explicación brillante, directa y buena. Esta debería ser la respuesta. – Battleroid

Cuestiones relacionadas