如何让tkinter菜单选项仅执行其绑定的对应函数?
问题描述
我是Python新手,正在Windows系统学习开发基础tkinter GUI应用。我定义了menubar(菜单栏)并添加了一个菜单,接着为该菜单添加多个选项,但点击任意菜单选项时,所有绑定的命令都会执行,想请教如何实现仅运行被点击菜单对应的函数?
最小可复现代码(MWE)
问题:无论点击哪个菜单,都会执行所有菜单选项的函数
import tkinter as tk from tkinter import ttk,messagebox def show_child_win(win,text=''): win_child = tk.Toplevel(win) var_l1 = tk.StringVar() l1 = tk.Label(win_child,textvariable=var_l1) l1.grid(row=0, column=0) var_l1.set(text) win_child.after(3*1000,lambda: win_child.destroy()) win = tk.Tk() menubar = tk.Menu(win) menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="Scripts", menu=menu) dict_label_func = { 'function_01': lambda win: show_child_win(win,text='function_01'), 'function_02': lambda win: show_child_win(win,text='function_02'), 'last_function': lambda win: show_child_win(win,text='last_function') } for label, func in dict_label_func.items(): menu.add_command(label=label,command = lambda x=win: func(x)) win.config(menu=menubar) win.mainloop()
解决方法
问题出在循环里的lambda变量捕获逻辑:当前代码中,lambda里的func会随着循环迭代被不断覆盖,最终所有菜单命令都指向最后一次迭代的func,所以点任何菜单都会触发所有函数。
方式一:用lambda默认参数捕获当前迭代的函数
修改循环内的命令绑定,给lambda新增默认参数f=func,这样每次迭代时都会把当前的func值固定下来,不会被后续迭代覆盖:
for label, func in dict_label_func.items(): menu.add_command(label=label, command=lambda x=win, f=func: f(x))
方式二:简化逻辑,直接绑定带参数的目标函数
可以去掉多层lambda的字典结构,直接在循环里把菜单标签作为参数传给show_child_win,更直观:
# 替换原有的dict_label_func和循环部分 menu_options = ['function_01', 'function_02', 'last_function'] for label in menu_options: menu.add_command(label=label, command=lambda x=win, txt=label: show_child_win(x, text=txt))
修改后的完整代码(方式一示例)
import tkinter as tk from tkinter import ttk,messagebox def show_child_win(win,text=''): win_child = tk.Toplevel(win) var_l1 = tk.StringVar() l1 = tk.Label(win_child,textvariable=var_l1) l1.grid(row=0, column=0) var_l1.set(text) win_child.after(3*1000,lambda: win_child.destroy()) win = tk.Tk() menubar = tk.Menu(win) menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="Scripts", menu=menu) dict_label_func = { 'function_01': lambda win: show_child_win(win,text='function_01'), 'function_02': lambda win: show_child_win(win,text='function_02'), 'last_function': lambda win: show_child_win(win,text='last_function') } for label, func in dict_label_func.items(): menu.add_command(label=label, command=lambda x=win, f=func: f(x)) win.config(menu=menubar) win.mainloop()
内容的提问来源于stack exchange,提问作者dallascow
相关产品推荐
相关产品推荐

