tkinter grid identification is not working, cannot identify each pixel
Question:
I know that this is quite an individual question, but I think it is a problem in Tkinter as I regularly encounter similar problem that I workaround and the answers could be beneficial for others as well.
The script is:
from tkinter import *
import random
class gui:
def __init__(self):
win=self.win=Tk()
win.title('Ploters Data!')
def identifier(self,x,y):
print('id',x,y)
def createGraph(self,rows,columns):
for xrow in range(rows+1):
for ycolumn in range(columns+1):
if xrow == 0 or ycolumn == 0:
text = '--'
if xrow == 0:
if ycolumn==5:
text='5'
if ycolumn==10:
text='10'
if ycolumn == 0:
if xrow==5:
text='5'
if xrow==10:
text='10'
if xrow == ycolumn == 0:
text='[]'
pixel = Button(self.win,padx=10,pady=10,text=text)
# print('click',xrow,ycolumn)
pixel.config(command=lambda button=pixel: self.identifier(xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
else:
pixel = Button(self.win,padx=10,pady=10)
# print('click',xrow,ycolumn)
pixel.config(command=lambda button=pixel: self.identifier(xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
# print(xrow,ycolumn)
self.win.mainloop()
s=gui()
s.createGraph(15,10)
The specific problem is that when you click a button on the grid it doesn’t give the correct ‘coordinates’, instead, it gives the last button.
Answers:
I think you overwrite the lambda function, which is somehow mutable in this example. I don’t know why this happens (had the same problem with tkinter GUIs) but I know a simple workaround, now.
If you define a class that takes a function and a series of arguments and keyword arguments and just calls the function with these arguments, you can reference it as command in buttons. Using this workaround, you can omit the lambda and just call functions with arguments:
from tkinter import *
import random
class CMD: #Auxilliary function for callbacks using parameters. Syntax: CMD(function, argument1, argument2, ...)
def __init__(s1, func, *args):
s1.func = func
s1.args = args
def __call__(s1, *args):
args = s1.args+args
s1.func(*args)
class gui:
def __init__(self):
win=self.win=Tk()
win.title('Ploters Data!')
def identifier(self,x,y):
print('id',x,y)
def createGraph(self,rows,columns):
for xrow in range(rows+1):
for ycolumn in range(columns+1):
if xrow == 0 or ycolumn == 0:
text = '--'
if xrow == 0:
if ycolumn==5:
text='5'
if ycolumn==10:
text='10'
if ycolumn == 0:
if xrow==5:
text='5'
if xrow==10:
text='10'
if xrow == ycolumn == 0:
text='[]'
pixel = Button(self.win,padx=10,pady=10,text=text,command=CMD(self.identifier,xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
else:
pixel = Button(self.win,padx=10,pady=10,command=CMD(self.identifier,xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
# print(xrow,ycolumn)
self.win.mainloop()
s=gui()
s.createGraph(15,10)
Using this small change, your program works fine.
I know that this is quite an individual question, but I think it is a problem in Tkinter as I regularly encounter similar problem that I workaround and the answers could be beneficial for others as well.
The script is:
from tkinter import *
import random
class gui:
def __init__(self):
win=self.win=Tk()
win.title('Ploters Data!')
def identifier(self,x,y):
print('id',x,y)
def createGraph(self,rows,columns):
for xrow in range(rows+1):
for ycolumn in range(columns+1):
if xrow == 0 or ycolumn == 0:
text = '--'
if xrow == 0:
if ycolumn==5:
text='5'
if ycolumn==10:
text='10'
if ycolumn == 0:
if xrow==5:
text='5'
if xrow==10:
text='10'
if xrow == ycolumn == 0:
text='[]'
pixel = Button(self.win,padx=10,pady=10,text=text)
# print('click',xrow,ycolumn)
pixel.config(command=lambda button=pixel: self.identifier(xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
else:
pixel = Button(self.win,padx=10,pady=10)
# print('click',xrow,ycolumn)
pixel.config(command=lambda button=pixel: self.identifier(xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
# print(xrow,ycolumn)
self.win.mainloop()
s=gui()
s.createGraph(15,10)
The specific problem is that when you click a button on the grid it doesn’t give the correct ‘coordinates’, instead, it gives the last button.
I think you overwrite the lambda function, which is somehow mutable in this example. I don’t know why this happens (had the same problem with tkinter GUIs) but I know a simple workaround, now.
If you define a class that takes a function and a series of arguments and keyword arguments and just calls the function with these arguments, you can reference it as command in buttons. Using this workaround, you can omit the lambda and just call functions with arguments:
from tkinter import *
import random
class CMD: #Auxilliary function for callbacks using parameters. Syntax: CMD(function, argument1, argument2, ...)
def __init__(s1, func, *args):
s1.func = func
s1.args = args
def __call__(s1, *args):
args = s1.args+args
s1.func(*args)
class gui:
def __init__(self):
win=self.win=Tk()
win.title('Ploters Data!')
def identifier(self,x,y):
print('id',x,y)
def createGraph(self,rows,columns):
for xrow in range(rows+1):
for ycolumn in range(columns+1):
if xrow == 0 or ycolumn == 0:
text = '--'
if xrow == 0:
if ycolumn==5:
text='5'
if ycolumn==10:
text='10'
if ycolumn == 0:
if xrow==5:
text='5'
if xrow==10:
text='10'
if xrow == ycolumn == 0:
text='[]'
pixel = Button(self.win,padx=10,pady=10,text=text,command=CMD(self.identifier,xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
else:
pixel = Button(self.win,padx=10,pady=10,command=CMD(self.identifier,xrow,ycolumn))
pixel.grid(row=xrow,column=ycolumn)
# print(xrow,ycolumn)
self.win.mainloop()
s=gui()
s.createGraph(15,10)
Using this small change, your program works fine.