¿Cómo puedo identificar botones, creados en un bucle?

Estoy tratando de progtwigr un juego de buscaminas en python usando tkinter. Comencé creando una cuadrícula de botones utilizando una lista bidimensional de 10×10. Luego creé cada botón usando un bucle, así no tengo que crear manualmente cada botón y recortarlos.

self.b=[[0 for x in range(1,12)] for y in range(1,12)] #The 2 dimensional list for self.i in range(1,11): for self.j in range(1,11): self.b[self.i][self.j]=tkinter.Button(root,text = (" "),command = lambda: self.delete()) # creating the button self.b[self.i][self.j].place(x=xp,y=yp) # placing the button xp+=26 #because the width and height of the button is 26 yp+=26 xp=0 

Básicamente quiero que el botón desaparezca al ser presionado. El problema es que no sé cómo permitir que el progtwig elimine específicamente el botón que presioné, ya que todos los botones son exactamente iguales. Al crear la función de borrado:

 def delete(self): self.b[???][???].destroy() 

No sé cómo permitir que el progtwig sepa qué botón fue el que presionó el usuario, para que pueda eliminar ese botón específico.

La pregunta: ¿hay una manera de permitir que cada botón tenga algo único que le permita diferenciarlo de los otros botones? ¿Asigne a cada botón una coordenada específica, de modo que cuando se presiona el botón (2,3), los números 2 y 3 pasan a la función de eliminación, de modo que la función de eliminación puede eliminar el botón (2,3)?

Al crear botones en un bucle, podemos crear (en realidad obtener) la identidad única.

Por ejemplo: si creamos un botón:

 button = Button(master, text="text") 

Podemos identificarlo de inmediato:

 print(button) >  

Si almacenamos esta identidad en una lista y asignamos un comando a los botones, vinculados a su índice durante la creación, podemos obtener su identidad específica al presionarlos.

Lo único que tenemos que hacer es buscar la identidad del botón por índice, una vez que se presiona el botón.

Para poder establecer un comando para los botones con el índice como argumento , usamos functoolspartial .

Ejemplo simplificado ( python3 )

En el ejemplo simplificado a continuación, creamos los botones en un bucle, agregamos sus identidades a la lista ( button_identities ). Se busca la identidad buscándola con: bname = (button_identities[n]) .

Ahora que tenemos la identidad, podemos hacer que el botón haga cualquier cosa , incluida la edición o el asesinato, ya que tenemos su identidad.

En el siguiente ejemplo, al presionar el botón se cambiará su etiqueta a “clic”

introduzca la descripción de la imagen aquí

 from tkinter import * from functools import partial win = Tk() button_identities = [] def change(n): # function to get the index and the identity (bname) print(n) bname = (button_identities[n]) bname.configure(text = "clicked") for i in range(5): # creating the buttons, assigning a unique argument (i) to run the function (change) button = Button(win, width=10, text=str(i), command=partial(change, i)) button.pack() # add the button's identity to a list: button_identities.append(button) # just to show what happens: print(button_identities) win.mainloop() 

O si lo hacemos destruiremos los botones una vez pulsados:

introduzca la descripción de la imagen aquí

 from tkinter import * from functools import partial win = Tk() button_identities = [] def change(n): # function to get the index and the identity (bname) print(n) bname = (button_identities[n]) bname.destroy() for i in range(5): # creating the buttons, assigning a unique argument (i) to run the function (change) button = Button(win, width=10, text=str(i), command=partial(change, i)) button.place(x=0, y=i*30) # add the button's identity to a list: button_identities.append(button) # just to show what happens: print(button_identities) win.mainloop() 

Código simplificado para su matriz (python3):

En el siguiente ejemplo, utilicé el producto de itertools () para generar las coordenadas de la matriz.

introduzca la descripción de la imagen aquí

 #!/usr/bin/env python3 from tkinter import * from functools import partial from itertools import product # produce the set of coordinates of the buttons positions = product(range(10), range(10)) button_ids = [] def change(i): # get the button's identity, destroy it bname = (button_ids[i]) bname.destroy() win = Tk() frame = Frame(win) frame.pack() for i in range(10): # shape the grid setsize = Canvas(frame, width=30, height=0).grid(row=11, column=i) setsize = Canvas(frame, width=0, height=30).grid(row=i, column=11) for i, item in enumerate(positions): button = Button(frame, command=partial(change, i)) button.grid(row=item[0], column=item[1], sticky="n,e,s,w") button_ids.append(button) win.minsize(width=270, height=270) win.title("Too many squares") win.mainloop() 

Más opciones, destruyendo un botón por coordenadas.

Dado que el product() también produce las coordenadas x, y del botón (s), podemos almacenar las coordenadas (en coords en el ejemplo) e identificar la identidad del botón por coordenadas.

En el siguiente ejemplo, la función hide_by_coords(): destruye el botón por coordenadas, lo que puede ser útil en un juego similar a un minesweeper . Como ejemplo, al hacer clic en un botón también se destruye el de la derecha:

 #!/usr/bin/env python3 from tkinter import * from functools import partial from itertools import product positions = product(range(10), range(10)) button_ids = []; coords = [] def change(i): bname = (button_ids[i]) bname.destroy() # destroy another button by coordinates # (next to the current one in this case) button_nextto = coords[i] button_nextto = (button_nextto[0] + 1, button_nextto[1]) hide_by_coords(button_nextto) def hide_by_coords(xy): # this function can destroy a button by coordinates # in the matrix (topleft = (0, 0). Argument is a tuple try: index = coords.index(xy) button = button_ids[index] button.destroy() except (IndexError, ValueError): pass win = Tk() frame = Frame(win) frame.pack() for i in range(10): # shape the grid setsize = Canvas(frame, width=30, height=0).grid(row=11, column=i) setsize = Canvas(frame, width=0, height=30).grid(row=i, column=11) for i, item in enumerate(positions): button = Button(frame, command=partial(change, i)) button.grid(column=item[0], row=item[1], sticky="n,e,s,w") button_ids.append(button) coords.append(item) win.minsize(width=270, height=270) win.title("Too many squares") win.mainloop() 

Si solo desea destruir el widget de botón, la forma más sencilla es agregar la callback después de crear el botón. P.ej,

 import Tkinter as tk grid_size = 10 root = tk.Tk() blank = " " * 3 for y in range(grid_size): for x in range(grid_size): b = tk.Button(root, text=blank) b.config(command=b.destroy) b.grid(column=x, row=y) root.mainloop() 

Sin embargo, si necesita realizar un procesamiento adicional en su callback, como actualizar su cuadrícula de botones, es conveniente almacenar los índices de cuadrícula del Botón como un atributo del objeto Botón.

 from __future__ import print_function import Tkinter as tk class ButtonDemo(object): def __init__(self, grid_size): self.grid_size = grid_size self.root = tk.Tk() self.grid = self.button_grid() self.root.mainloop() def button_grid(self): grid = [] blank = " " * 3 for y in range(self.grid_size): row = [] for x in range(self.grid_size): b = tk.Button(self.root, text=blank) b.config(command=lambda widget=b: self.delete_button(widget)) b.grid(column=x, row=y) #Store row and column indices as a Button attribute b.position = (y, x) row.append(b) grid.append(row) return grid def delete_button(self, widget): y, x = widget.position print("Destroying", (y, x)) widget.destroy() #Mark this button as invalid self.grid[y][x] = None ButtonDemo(grid_size=10) 

Ambos scripts son compatibles con Python 3, solo cambia la línea de importación a

 import tkinter as tk 

Intenta modificar tu código de la siguiente manera:

 self.b=[[0 for x in range(10)] for y in range(10)] #The 2 dimensional list xp = yp = 0 for i in range(10): for j in range(10): self.b[i][j]=tkinter.Button(root,text=" ",command=lambda i=i,j=j: self.delete(i,j)) # creating the button self.b[i][j].place(x=xp,y=yp) # placing the button xp+=26 #because the width and height of the button is 26 yp+=26 xp=0 

y:

 def delete(self, i, j): self.b[i][j].destroy() 

El siguiente código genera 12 botones, 4 en cada fila. El botón particular requerido para ser editado se llama similar a llamar a un elemento de matriz. Como ejemplo, un botón [1,1] se ha editado para el color de fondo y el botón [2,2] se ha editado para el texto y el color de primer plano. El progtwig está probado en python3.6 pycharm console

 from tkinter import * root=Tk() Buts={} for r in range(3): for c in range(4): Buts[(r,c)]=Button(root,text='%s/%s'%(r,c),borderwidth=10) Buts[r,c].grid(row=r,column=c) Buts[1,1]['bg']='red' Buts[2,2]['text']=['BUTTON2'] Buts[2,2]['fg']=['blue'] root.mainloop()