I am having problems binding key events to TkInter widgets. I have tried many example from the websites, but with no luck. I notice that none of the examples are using classes. I am defining my GUI inside a class; could that effect the binding? If anyone could let me know id be grateful. thanks
self.label_var = StringVar()
self.label = CTkLabel(
master=self.frame,
width=label_width,
height=height,
fg_color=background,
text_color=label_colour,
textvariable=self.label_var,
)
self.label.bind("<Button-1>", lambda e: print(e))
The full class is as below. The idea was to wrap all the boiler-plate code together but also to allow me to have the label at either side of the switch.
class LabelledSwitch:
def __init__(
self,
frame: CTkFrame,
row: int,
column: int,
padx: Tuple[int, int],
pady: Tuple[int, int],
width: int,
height: int,
background: str,
label_width: int,
label_colour: str,
label_align: str,
label_left: bool,
switch_width: int,
align: str,
callback,
):
self.frame = CTkFrame(
frame, width=width, height=height, bg_color=background, fg_color=None
)
self.frame.grid(row=row, column=column, padx=0, pady=0)
self.frame.grid_rowconfigure(index=0, weight=1)
self.frame.grid_columnconfigure(index=0, weight=0)
self.frame.grid_columnconfigure(index=1, weight=1)
if align == "LEFT":
self.frame.grid(sticky="w")
if align == "RIGHT":
self.frame.grid(sticky="e")
if align == "CENTER":
self.frame.grid(sticky="")
if align == "STRETCH":
self.frame.grid(sticky="we")
self.label_var = StringVar()
self.label = CTkLabel(
master=self.frame,
width=label_width,
height=height,
fg_color=background,
text_color=label_colour,
textvariable=self.label_var,
)
self.label.bind("<Button-1>", lambda e: print(e))
if label_left:
self.label.grid(
row=0,
column=0,
padx=(padx[0], 0),
pady=(pady[0], pady[1]),
)
else:
self.label.grid(
row=0,
column=1,
padx=(5, padx[1]),
pady=(pady[0], pady[1]),
)
if label_align == "LEFT":
self.label.configure(anchor="w")
if label_align == "RIGHT":
self.label.configure(anchor="e")
if label_align == "CENTER":
self.label.configure(anchor="we")
if label_align == "STRETCH":
self.label.configure(anchor="we")
self.switch_var = StringVar()
self.switch = CTkSwitch(
master=self.frame,
width=switch_width,
height=height,
background="GREEN",
bg_color=background,
text="",
variable=self.switch_var,
onvalue="on",
offvalue="off",
command=callback,
)
if label_left:
self.switch.grid(
row=0,
column=1,
padx=(5, padx[1]),
pady=(pady[0], pady[1]),
)
else:
self.switch.grid(
row=0,
column=0,
padx=(padx[0], 0),
pady=(pady[0], pady[1]),
)
if align == "LEFT":
self.switch.grid(sticky="w")
if align == "RIGHT":
self.switch.grid(sticky="e")
if align == "CENTER":
self.switch.grid(sticky="we")
if align == "STRETCH":
self.switch.grid(sticky="we")
CodePudding user response:
This appears to be a limitation of the CTkLabel widget. When you click on the widget, you actually click on a label embedded on the widget. Since your binding isn't on that internal embedded label, your binding won't trigger.
You can see this by printing out the value of self.label
, and then adding this binding:
root.bind_all("<1>", lambda event: print(event.widget))
The output will show that self.label
is named something like .!root.!frame.!ctklabel
, but the widget that receives the click is something like .!root.!frame.!ctklabel.!label
You should probably file a bug with the customtkinter project.
As a workaround, you can bind to all of the inner child widgets of the label like so:
for child in self.label.winfo_children():
child.bind("<Button-1>", lambda e: print(e))