Python Tkinter级联菜单命令未执行。

huangapple go评论65阅读模式
英文:

Python Tkinter cascaded menu command not executing

问题

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 any way 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 demonstrates 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 the 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 in 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 color 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.

英文:

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(&#39;Tkinter Validation Demo&#39;)

        self.create_widgets()

    @staticmethod
    def print_bg_color(button, button_id):
        colour = button.cget(&#39;bg&#39;)
        print(f&#39;Button {button_id} colour is {colour}&#39;)

    @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 = [&#39;red&#39;, &#39;orange&#39;, &#39;yellow&#39;, &#39;green&#39;, &#39;blue&#39;, &#39;indigo&#39;, &#39;violet&#39;]
        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=&quot;Print colour&quot;,
                                     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=&quot;Print colour&quot;,
                                 command=lambda btn=button, button_id=i:
                                 self.print_bg_color(button=btn, button_id=button_id))
            context_menu.add_cascade(label=&#39;Cascade&#39;, menu=sub_menu)

            button.bind(&quot;&lt;Button-3&gt;&quot;,
                        lambda event, menu=context_menu, button_id=i:
                        self._context_menu(event, menu))


if __name__ == &#39;__main__&#39;:
    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(&quot;info&quot;, &quot;patchlevel&quot;))

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/

答案1

得分: 1

代码问题:问题中的代码中,子菜单被设置为button的一个元素:

sub_menu = tk.Menu(button, tearoff=False)

然而,这会导致子菜单显示正确,但不能点击(在Ubuntu、Python 3.10.6、Tkinter 8.6上重现)。当您将子菜单设置为context_menu的一个元素时,它会起作用:

sub_menu = tk.Menu(context_menu, tearoff=False)
英文:

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)

huangapple
  • 本文由 发表于 2023年5月8日 00:06:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76194973.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定