如何在Tkinter的Menubutton菜单内添加滚动条?
我正在开发一款可选择文本字体的Tkinter应用,主窗口中有一个Menubutton,内含约347种可选字体,希望为该菜单添加滚动条以方便浏览。以下是无滚动条的实现代码:
import tkinter as tk from tkinter import Menu, FLAT # 假设main_window已定义,font_nameX和fontX函数已实现 main_window = tk.Tk() # Menu button fonts_MenuButton = tk.Menubutton(main_window, text="v", bg="WHITE", fg="BLACK", activebackground="WHITE", font=("Arial", 9), relief=FLAT) # Menu for choosing font fonts_MenuButton.pack(side="left", fill="x", expand=False) # Position the menu in which you can choose any font fonts_MenuButton.menu = Menu(fonts_MenuButton, tearoff = 0) # Create a menu fonts_MenuButton["menu"] = fonts_MenuButton.menu # Fonts fonts_MenuButton.menu.add_command(label=font_name1, font=(font_name1, 13), command=font1) # Font 1 button fonts_MenuButton.menu.add_command(label=font_name2, font=(font_name2, 13), command=font2) # Font 2 button fonts_MenuButton.menu.add_command(label=font_name3, font=(font_name3, 13), command=font3) # Font 3 button fonts_MenuButton.menu.add_command(label=font_name4, font=(font_name4, 13), command=font4) # Font 4 button fonts_MenuButton.menu.add_command(label=font_name5, font=(font_name5, 13), command=font5) # Font 5 button fonts_MenuButton.menu.add_command(label=font_name6, font=(font_name6, 13), command=font6) # Font 6 button fonts_MenuButton.menu.add_command(label=font_name7, font=(font_name7, 13), command=font7) # Font 7 button # ... 剩余340种字体的添加代码
其中font_name开头的变量用于存储字体名称,fontX函数为菜单按钮的点击回调函数。请问是否有可行的实现方法?
可行实现方法
Tkinter原生的Menu组件并不直接支持滚动条,不过有两种实用的替代方案:
方案1:使用ttk.Combobox替代Menubutton
ttk.Combobox的下拉列表自带滚动功能,适配大量选项场景,代码实现简洁:
import tkinter as tk from tkinter import ttk def on_font_selected(event): selected_font = font_combobox.get() # 替换为你的字体设置逻辑,比如调用对应回调函数 print(f"选择了字体:{selected_font}") main_window = tk.Tk() # 获取系统所有可用字体并排序 available_fonts = list(tk.font.families()) available_fonts.sort() # 创建带滚动的下拉选择框 font_combobox = ttk.Combobox(main_window, values=available_fonts, state="readonly", font=("Arial",9)) font_combobox.pack(side="left", fill="x", expand=False) font_combobox.bind("<<ComboboxSelected>>", on_font_selected) main_window.mainloop()
方案2:自定义带滚动条的弹出菜单
如果需要保留Menubutton的弹出式体验,可以通过Canvas+Frame+Scrollbar组合模拟带滚动的菜单:
import tkinter as tk from tkinter import FLAT def show_scrollable_menu(event): # 销毁已存在的菜单窗口 if hasattr(main_window, "scroll_menu_win"): main_window.scroll_menu_win.destroy() # 创建无边框的弹出窗口 main_window.scroll_menu_win = tk.Toplevel(main_window) main_window.scroll_menu_win.overrideredirect(True) # 定位到Menubutton下方 x = main_window.winfo_rootx() + fonts_MenuButton.winfo_x() y = main_window.winfo_rooty() + fonts_MenuButton.winfo_y() + fonts_MenuButton.winfo_height() main_window.scroll_menu_win.geometry(f"+{x}+{y}") # 配置滚动条与画布 scrollbar = tk.Scrollbar(main_window.scroll_menu_win) scrollbar.pack(side="right", fill="y") canvas = tk.Canvas(main_window.scroll_menu_win, yscrollcommand=scrollbar.set) canvas.pack(side="left", fill="both", expand=True) scrollbar.config(command=canvas.yview) # 创建承载字体按钮的Frame font_frame = tk.Frame(canvas) canvas.create_window((0,0), window=font_frame, anchor="nw") # 添加所有字体按钮 available_fonts = list(tk.font.families()) available_fonts.sort() for font_name in available_fonts: btn = tk.Button(font_frame, text=font_name, font=(font_name,13), command=lambda fn=font_name: select_font(fn)) btn.pack(fill="x", expand=True) # 更新画布滚动区域 font_frame.update_idletasks() canvas.config(scrollregion=canvas.bbox("all")) def select_font(font_name): # 替换为你的字体设置逻辑 print(f"选择了字体:{font_name}") # 关闭滚动菜单窗口 main_window.scroll_menu_win.destroy() main_window = tk.Tk() # 原Menubutton fonts_MenuButton = tk.Menubutton(main_window, text="v", bg="WHITE", fg="BLACK", activebackground="WHITE", font=("Arial", 9), relief=FLAT) fonts_MenuButton.pack(side="left", fill="x", expand=False) # 绑定点击事件显示自定义滚动菜单 fonts_MenuButton.bind("<Button-1>", show_scrollable_menu) main_window.mainloop()
方案对比
- 方案1实现简单,自带系统样式和滚动功能,适合快速开发;
- 方案2更贴近原生Menubutton的弹出体验,自定义程度更高,但代码量稍大。
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

