You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter Menubutton含子菜单的标签点击失效问题求助

Tkinter Menubutton级联项点击无响应问题(Windows平台)

问题根源

在Windows系统中,使用Menu.add_cascade()同时指定menu(子菜单)和command参数时,command会被忽略。这是因为带子菜单的级联菜单项默认功能是展开子菜单,Windows平台的Tkinter实现会优先处理子菜单展开逻辑,直接跳过命令回调。

另外,你给无子女菜单项使用add_cascade也不合适,这类项应该用add_command来创建。

修复方案

通过给带子菜单的级联菜单项绑定点击事件,替代无效的command参数。以下是修改后的完整代码:

import tkinter as tk
from tkinter import ttk


class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title('App')
        self.geometry('200x100')

        self.category_button = ttk.Menubutton(self, text='Select')
        self.create_categories_menu(self.category_button)

        self.category_button.pack(expand=True)

    def create_categories_menu(self, category_button):
        categories = {
            'Foo': {
                'ID': 1
            },
            'Bar': {
                'ID': 2,
                'SubCategory': {
                    'Baz': {
                        'ID': 3
                    }
                }
            }
        }

        top_menu = tk.Menu(category_button, tearoff=False)
        category_button.configure(menu=top_menu)

        self.create_sub_category(categories, category_button, top_menu)

    def create_sub_category(self, categories, category_button, top_menu):
        for category in categories:
            if 'SubCategory' not in categories[category]:
                # 无子女菜单用add_command而非add_cascade
                top_menu.add_command(
                    label=category,
                    command=lambda c=category: self.set_button_label(category_button, c)
                )
            else:
                menu = tk.Menu(top_menu, tearoff=False)
                # 添加级联项,仅指定子菜单,不设command
                top_menu.add_cascade(label=category, menu=menu)
                # 获取当前级联项的索引,绑定点击事件
                item_index = top_menu.index(tk.END)
                top_menu.bind(f'<Button-1>@{item_index}', lambda e, c=category: self.set_button_label(category_button, c))

                self.create_sub_category(
                    categories[category]['SubCategory'],
                    category_button,
                    menu
                )
    
    def set_button_label(self, button, name):
        button.configure(text=name)


if __name__ == '__main__':
    MainWindow().mainloop()

关键修改点

  1. 将无子女菜单项的add_cascade替换为add_command,这是Tkinter创建普通可点击菜单项的标准用法。
  2. 移除带子女级联项的command参数,改为绑定<Button-1>@{index}事件,确保鼠标点击时触发命令。
  3. 简化了create_categories_menu的返回值逻辑,原代码中重新赋值category_button是多余的。

额外说明

  • 使用<Button-1>@{index}可以精准绑定到指定的菜单项,避免事件冒泡影响其他项。
  • 如果你需要支持键盘导航触发命令,可以改用<<MenuSelect>>事件,但该事件会在菜单项被选中(包括键盘箭头导航)时触发,按需选择即可。

内容的提问来源于stack exchange,提问作者Tolga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:27:44