I have a problem, which I am trying to solve, and have reproduced it with the code below.
The issue that I have, is that I can get the specified command to work from a main menu item, but when the same command is included in a cascade menu, it doesn't appear to execute.
I'm not sure whether this is in anyway to do with my requirements, which are that I need to render a grid of buttons and attach a context menu to each. Here is some code which I contrived which demonstrate the issue:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Tkinter Validation Demo')
self.create_widgets()
@staticmethod
def print_bg_color(button, button_id):
colour = button.cget('bg')
print(f'Button {button_id} colour is {colour}')
@staticmethod
def _context_menu(event: tk.Event = None, menu: tk.Menu = None):
menu.tk_popup(event.x_root, event.y_root)
def create_widgets(self):
colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
for i in range(0, 7):
button = tk.Button(master=self, bg=colors[i], width=10, height=10)
button.grid(row=0, column=i)
context_menu = tk.Menu(button, tearoff=False)
# Add print option to main menu
context_menu.add_command(label="Print colour",
command=lambda btn=button, button_id=i:
self.print_bg_color(button=btn, button_id=button_id))
sub_menu = tk.Menu(button, tearoff=False)
# Add a print colour option on the sub menu
sub_menu.add_command(label="Print colour",
command=lambda btn=button, button_id=i:
self.print_bg_color(button=btn, button_id=button_id))
context_menu.add_cascade(label='Cascade', menu=sub_menu)
button.bind("<Button-3>",
lambda event, menu=context_menu, button_id=i:
self._context_menu(event, menu))
if __name__ == '__main__':
app = App()
app.mainloop()
When the above code is run, it allows you to right click on any of the rendered buttons, and select the "Print color" from either the main context menu, or from a cascade option. The command bound to the event, simply obtains the colour of the button and prints it to the console. This works for the main context menu option, but the cascade menu entry does nothing, despite having the same command.
Any suggestions gratefully received.
Thanks.
UPDATE: Having determined that this only seems to be happening on my Linux Mint environment running Python 3.8 (it works on my Windows 10 with Python 3.10), I ran the script suggested by Nordine in the comments:
import tkinter
from platform import python_version
print(python_version())
root = tkinter.Tk()
print(root.tk.call("info", "patchlevel"))
The results showed as:
3.8.10
8.6.10
FURTHER UPDATE:
I just upgraded to Python 3.10 on my Linux Mint machine, and it still isn't working :o/
The submenu in the code in the question is set up as an element of button
:
sub_menu = tk.Menu(button, tearoff=False)
However, this causes the submenu to be displayed correctly but to not be clickable (reproduced on Ubuntu, Python 3.10.6, Tkinter 8.6). When you make the submenu an element of context_menu
then it does work:
sub_menu = tk.Menu(context_menu, tearoff=False)