Reputation: 690
I am trying to make a simple color picker for an application. I am generating an array of labels with different background colors. When the label is clicked, I want to put the hex color into an entry field in the parent widget.
Everything loads correctly, but it seems I am passing the bind event instance to my set_color method, and not actually the hex color. What am I doing wrong?
I could use buttons with commands, but those take longer to load.
# Python 2.7
import Tkinter as tk
from tkFont import Font
import math
class ColorPicker(tk.Toplevel):
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.parent = parent
self.title("ColorPicker")
self.frame = tk.Frame(self)
self.frame.pack()
self.buttonfont = Font(family="Arial", size=5)
ROW, COL = 0, 0
COLORS = xrange(1, int("FFFFFF", base=16), 50000)
for color in COLORS:
hexcolor = "#" + str(hex(color))[2:]
hexcolor += "0"*(7 - len(hexcolor))
l = tk.Label(self.frame, bg=hexcolor, text=hexcolor, font=self.buttonfont)
l.bind("<Button-1>", lambda x=hexcolor: self.set_color(x))
l.grid(row=ROW, column=COL)
ROW += 1
if ROW > math.sqrt(len(COLORS)):
ROW = 0
COL += 1
def set_color(self, color):
self.parent.entry_background_color.delete(0, tk.END)
self.parent.entry_background_color.insert(0, color)
self.destroy()
And here is a small example that runs and reproduces the behavior.
import Tkinter as tk
def p(s, *args):
print(s)
app = tk.Tk()
frame = tk.Frame(app)
frame.pack()
for i in range(3):
label = tk.Label(app, text="Press Me")
label.pack()
label.bind("<Button-1>", lambda i=i: p("Hello World {} times".format(i)))
app.mainloop()
Upvotes: 1
Views: 115
Reputation: 7176
Bind is generating an event which you must consume within the lambda:
l.bind("<Button-1>", lambda event, x=hexcolor: self.set_color(x))
# ^ ^
# consume event-------| | and then assign x
Otherwise lambda will assign the event to hexcolor
.
Update
As for the problems with labels not being responsive, I have not been able to reproduce that. I did however give it some thought and came up with a way of assigning ROW and COL which feels more pythonic:
import Tkinter as tk
import math
class ColorPicker(tk.Toplevel):
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.parent = parent
self.title("ColorPicker")
self.frame = tk.Frame(self)
self.frame.pack()
ROW, COL = 0, 0
COLORS = xrange(1, int("FFFFFF", base=16), 50000)
for count, color in enumerate(COLORS):
hexcolor = "#" + str(hex(color))[2:]
hexcolor += "0"*(7 - len(hexcolor))
ROW = count // int(math.sqrt(len(COLORS)))
COL = count % int(math.sqrt(len(COLORS)))
l = tk.Label(self.frame, bg=hexcolor, text=hexcolor)
l.bind("<Button-1>", lambda event, x=hexcolor: self.set_color(x))
l.grid(row=ROW, column=COL)
def set_color(self, color):
print color
root = tk.Tk()
app = ColorPicker(root)
Beware that I'm running Python 3.6.5 and there may be some differences.
Upvotes: 1