Menubutton(菜單按鈕)是Tkinter中用於創建下拉菜單的按鈕組件,通常與Menu組件結合使用。
基本用法
1. 導入和基本創建
import tkinter as tk
from tkinter import messagebox
# 創建主窗口
root = tk.Tk()
root.title("Menubutton組件詳解")
root.geometry("500x400")
2. 創建基本Menubutton
# 創建Menubutton
menubutton = tk.Menubutton(
root,
text="選擇選項", # 按鈕上顯示的文本
relief=tk.RAISED, # 按鈕樣式
direction='below' # 菜單彈出方向
)
menubutton.pack(pady=20)
# 創建關聯的Menu
menu = tk.Menu(menubutton, tearoff=0)
# 向菜單添加項目
menu.add_command(label="選項1", command=lambda: messagebox.showinfo("選擇", "你選擇了選項1"))
menu.add_command(label="選項2", command=lambda: messagebox.showinfo("選擇", "你選擇了選項2"))
menu.add_separator() # 分隔線
menu.add_command(label="選項3", command=lambda: messagebox.showinfo("選擇", "你選擇了選項3"))
# 將菜單關聯到Menubutton
menubutton.config(menu=menu)
root.mainloop()
完整功能示例
示例1:多功能Menubutton
import tkinter as tk
from tkinter import messagebox
class MenubuttonExample:
def __init__(self, root):
self.root = root
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("Menubutton完整示例")
self.root.geometry("600x500")
# 標題
title_label = tk.Label(self.root, text="Menubutton示例",
font=("Arial", 16, "bold"))
title_label.pack(pady=10)
# 創建多個Menubutton示例
self.create_basic_menubutton()
self.create_direction_menubuttons()
self.create_styled_menubutton()
self.create_complex_menubutton()
# 狀態顯示
self.status_label = tk.Label(self.root, text="請選擇一個選項",
font=("Arial", 10), fg="blue")
self.status_label.pack(pady=20)
def create_basic_menubutton(self):
"""創建基本Menubutton"""
frame = tk.LabelFrame(self.root, text="基本Menubutton", padx=10, pady=10)
frame.pack(fill="x", padx=20, pady=10)
menubutton = tk.Menubutton(
frame,
text="文件操作",
relief=tk.RAISED,
bg="lightblue"
)
menubutton.pack(pady=5)
# 創建菜單
menu = tk.Menu(menubutton, tearoff=0)
menubutton.config(menu=menu)
# 添加菜單項
menu.add_command(label="新建文件", command=lambda: self.update_status("新建文件"))
menu.add_command(label="打開文件", command=lambda: self.update_status("打開文件"))
menu.add_separator()
menu.add_command(label="保存", command=lambda: self.update_status("保存"))
menu.add_command(label="另存為", command=lambda: self.update_status("另存為"))
menu.add_separator()
menu.add_command(label="退出", command=lambda: self.update_status("退出"))
def create_direction_menubuttons(self):
"""創建不同方向的Menubutton"""
frame = tk.LabelFrame(self.root, text="不同方向", padx=10, pady=10)
frame.pack(fill="x", padx=20, pady=10)
directions_frame = tk.Frame(frame)
directions_frame.pack()
# 下方彈出
mb1 = tk.Menubutton(directions_frame, text="下方菜單", direction="below")
mb1.grid(row=0, column=0, padx=10, pady=5)
menu1 = tk.Menu(mb1, tearoff=0)
mb1.config(menu=menu1)
menu1.add_command(label="選項1", command=lambda: self.update_status("下方菜單-選項1"))
menu1.add_command(label="選項2", command=lambda: self.update_status("下方菜單-選項2"))
# 上方彈出
mb2 = tk.Menubutton(directions_frame, text="上方菜單", direction="above")
mb2.grid(row=0, column=1, padx=10, pady=5)
menu2 = tk.Menu(mb2, tearoff=0)
mb2.config(menu=menu2)
menu2.add_command(label="選項A", command=lambda: self.update_status("上方菜單-選項A"))
menu2.add_command(label="選項B", command=lambda: self.update_status("上方菜單-選項B"))
# 左側彈出
mb3 = tk.Menubutton(directions_frame, text="左側菜單", direction="left")
mb3.grid(row=1, column=0, padx=10, pady=5)
menu3 = tk.Menu(mb3, tearoff=0)
mb3.config(menu=menu3)
menu3.add_command(label="項目1", command=lambda: self.update_status("左側菜單-項目1"))
menu3.add_command(label="項目2", command=lambda: self.update_status("左側菜單-項目2"))
# 右側彈出
mb4 = tk.Menubutton(directions_frame, text="右側菜單", direction="right")
mb4.grid(row=1, column=1, padx=10, pady=5)
menu4 = tk.Menu(mb4, tearoff=0)
mb4.config(menu=menu4)
menu4.add_command(label="項目X", command=lambda: self.update_status("右側菜單-項目X"))
menu4.add_command(label="項目Y", command=lambda: self.update_status("右側菜單-項目Y"))
def create_styled_menubutton(self):
"""創建樣式化的Menubutton"""
frame = tk.LabelFrame(self.root, text="樣式化Menubutton", padx=10, pady=10)
frame.pack(fill="x", padx=20, pady=10)
# 帶圖標的Menubutton
mb1 = tk.Menubutton(
frame,
text="顏色選擇",
relief=tk.GROOVE,
bg="lightgreen",
fg="darkgreen",
font=("Arial", 10, "bold"),
padx=10,
pady=5
)
mb1.pack(pady=5)
menu1 = tk.Menu(mb1, tearoff=0, bg="lightyellow")
mb1.config(menu=menu1)
colors = [("紅色", "red"), ("綠色", "green"), ("藍色", "blue"),
("黃色", "yellow"), ("紫色", "purple")]
for color_name, color_code in colors:
menu1.add_command(
label=color_name,
command=lambda c=color_code, n=color_name: self.change_color(c, n)
)
# 禁用狀態的Menubutton
mb2 = tk.Menubutton(
frame,
text="禁用菜單 (點擊無效)",
relief=tk.SUNKEN,
state="disabled",
bg="lightgray"
)
mb2.pack(pady=5)
menu2 = tk.Menu(mb2, tearoff=0)
mb2.config(menu=menu2)
menu2.add_command(label="這個菜單被禁用")
def create_complex_menubutton(self):
"""創建複雜菜單結構的Menubutton"""
frame = tk.LabelFrame(self.root, text="複雜菜單結構", padx=10, pady=10)
frame.pack(fill="x", padx=20, pady=10)
menubutton = tk.Menubutton(
frame,
text="高級選項",
relief=tk.RAISED,
bg="lightcoral"
)
menubutton.pack(pady=5)
# 創建主菜單
main_menu = tk.Menu(menubutton, tearoff=0)
menubutton.config(menu=main_menu)
# 添加複選框菜單項
self.option1_var = tk.BooleanVar()
self.option2_var = tk.BooleanVar(value=True)
main_menu.add_checkbutton(
label="啓用選項1",
variable=self.option1_var,
command=self.toggle_option1
)
main_menu.add_checkbutton(
label="啓用選項2",
variable=self.option2_var,
command=self.toggle_option2
)
main_menu.add_separator()
# 添加單選按鈕菜單項
self.radio_var = tk.StringVar(value="option_a")
radio_menu = tk.Menu(main_menu, tearoff=0)
main_menu.add_cascade(label="單選選項", menu=radio_menu)
radio_options = [("選項A", "option_a"), ("選項B", "option_b"), ("選項C", "option_c")]
for text, value in radio_options:
radio_menu.add_radiobutton(
label=text,
variable=self.radio_var,
value=value,
command=lambda v=value: self.select_radio(v)
)
main_menu.add_separator()
# 添加級聯菜單
tools_menu = tk.Menu(main_menu, tearoff=0)
main_menu.add_cascade(label="工具", menu=tools_menu)
tools_menu.add_command(label="工具1", command=lambda: self.update_status("工具1"))
tools_menu.add_command(label="工具2", command=lambda: self.update_status("工具2"))
# 子菜單中的子菜單
sub_tools_menu = tk.Menu(tools_menu, tearoff=0)
tools_menu.add_cascade(label="更多工具", menu=sub_tools_menu)
sub_tools_menu.add_command(label="高級工具1", command=lambda: self.update_status("高級工具1"))
sub_tools_menu.add_command(label="高級工具2", command=lambda: self.update_status("高級工具2"))
def update_status(self, message):
"""更新狀態顯示"""
self.status_label.config(text=f"選擇: {message}")
def change_color(self, color, color_name):
"""更改顏色"""
self.status_label.config(text=f"選擇顏色: {color_name}", fg=color)
def toggle_option1(self):
"""切換選項1"""
status = "啓用" if self.option1_var.get() else "禁用"
self.update_status(f"選項1 {status}")
def toggle_option2(self):
"""切換選項2"""
status = "啓用" if self.option2_var.get() else "禁用"
self.update_status(f"選項2 {status}")
def select_radio(self, value):
"""選擇單選選項"""
self.update_status(f"選擇了 {value}")
if __name__ == "__main__":
root = tk.Tk()
app = MenubuttonExample(root)
root.mainloop()
實際應用示例
示例2:工具欄菜單
import tkinter as tk
from tkinter import messagebox
class ToolbarWithMenubuttons:
def __init__(self, root):
self.root = root
self.current_font = "Arial"
self.current_size = 12
self.current_color = "black"
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("工具欄菜單示例")
self.root.geometry("700x500")
# 創建工具欄
self.create_toolbar()
# 創建文本編輯區域
self.create_text_area()
# 狀態欄
self.create_statusbar()
def create_toolbar(self):
"""創建工具欄"""
toolbar = tk.Frame(self.root, bg="lightgray", height=40)
toolbar.pack(fill="x", padx=5, pady=5)
toolbar.pack_propagate(False) # 防止框架收縮
# 文件菜單按鈕
file_mb = tk.Menubutton(
toolbar,
text="文件",
relief=tk.RAISED,
bg="white"
)
file_mb.pack(side="left", padx=2, pady=2)
file_menu = tk.Menu(file_mb, tearoff=0)
file_mb.config(menu=file_menu)
file_menu.add_command(label="新建", command=self.new_file)
file_menu.add_command(label="打開", command=self.open_file)
file_menu.add_command(label="保存", command=self.save_file)
file_menu.add_separator()
file_menu.add_command(label="退出", command=self.root.quit)
# 編輯菜單按鈕
edit_mb = tk.Menubutton(
toolbar,
text="編輯",
relief=tk.RAISED,
bg="white"
)
edit_mb.pack(side="left", padx=2, pady=2)
edit_menu = tk.Menu(edit_mb, tearoff=0)
edit_mb.config(menu=edit_menu)
edit_menu.add_command(label="撤銷", command=self.undo)
edit_menu.add_command(label="重做", command=self.redo)
edit_menu.add_separator()
edit_menu.add_command(label="剪切", command=self.cut)
edit_menu.add_command(label="複製", command=self.copy)
edit_menu.add_command(label="粘貼", command=self.paste)
# 字體菜單按鈕
font_mb = tk.Menubutton(
toolbar,
text="字體",
relief=tk.RAISED,
bg="white"
)
font_mb.pack(side="left", padx=2, pady=2)
font_menu = tk.Menu(font_mb, tearoff=0)
font_mb.config(menu=font_menu)
# 字體選擇子菜單
font_family_menu = tk.Menu(font_menu, tearoff=0)
font_menu.add_cascade(label="字體族", menu=font_family_menu)
fonts = ["Arial", "Times New Roman", "Courier New", "Verdana", "Georgia"]
for font in fonts:
font_family_menu.add_command(
label=font,
command=lambda f=font: self.change_font_family(f)
)
# 字號選擇子菜單
font_size_menu = tk.Menu(font_menu, tearoff=0)
font_menu.add_cascade(label="字號", menu=font_size_menu)
sizes = [8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32]
for size in sizes:
font_size_menu.add_command(
label=str(size),
command=lambda s=size: self.change_font_size(s)
)
font_menu.add_separator()
font_menu.add_command(label="粗體", command=self.make_bold)
font_menu.add_command(label="斜體", command=self.make_italic)
# 顏色菜單按鈕
color_mb = tk.Menubutton(
toolbar,
text="顏色",
relief=tk.RAISED,
bg="white"
)
color_mb.pack(side="left", padx=2, pady=2)
color_menu = tk.Menu(color_mb, tearoff=0)
color_mb.config(menu=color_menu)
colors = [
("黑色", "black"),
("紅色", "red"),
("綠色", "green"),
("藍色", "blue"),
("黃色", "yellow"),
("紫色", "purple"),
("橙色", "orange")
]
for color_name, color_code in colors:
color_menu.add_command(
label=color_name,
command=lambda c=color_code: self.change_text_color(c)
)
# 對齊菜單按鈕
align_mb = tk.Menubutton(
toolbar,
text="對齊",
relief=tk.RAISED,
bg="white"
)
align_mb.pack(side="left", padx=2, pady=2)
align_menu = tk.Menu(align_mb, tearoff=0)
align_mb.config(menu=align_menu)
align_menu.add_command(label="左對齊", command=self.align_left)
align_menu.add_command(label="居中", command=self.align_center)
align_menu.add_command(label="右對齊", command=self.align_right)
align_menu.add_command(label="兩端對齊", command=self.align_justify)
def create_text_area(self):
"""創建文本編輯區域"""
text_frame = tk.Frame(self.root)
text_frame.pack(fill="both", expand=True, padx=10, pady=10)
# 滾動條
scrollbar = tk.Scrollbar(text_frame)
scrollbar.pack(side="right", fill="y")
# 文本框
self.text_widget = tk.Text(
text_frame,
wrap="word",
yscrollcommand=scrollbar.set,
font=(self.current_font, self.current_size),
fg=self.current_color
)
self.text_widget.pack(side="left", fill="both", expand=True)
scrollbar.config(command=self.text_widget.yview)
# 插入示例文本
self.text_widget.insert("1.0", "這是一個文本編輯器示例。\n您可以使用工具欄上的菜單按鈕來格式化文本。")
def create_statusbar(self):
"""創建狀態欄"""
self.statusbar = tk.Label(
self.root,
text="就緒 | 字體: Arial 12pt | 顏色: 黑色",
relief="sunken",
anchor="w"
)
self.statusbar.pack(fill="x", side="bottom")
# 文件操作方法
def new_file(self):
self.text_widget.delete("1.0", "end")
self.update_status("新建文件")
def open_file(self):
messagebox.showinfo("打開", "打開文件功能")
def save_file(self):
messagebox.showinfo("保存", "保存文件功能")
# 編輯操作方法
def undo(self):
try:
self.text_widget.edit_undo()
except tk.TclError:
pass
def redo(self):
try:
self.text_widget.edit_redo()
except tk.TclError:
pass
def cut(self):
try:
self.text_widget.event_generate("<<Cut>>")
except tk.TclError:
pass
def copy(self):
try:
self.text_widget.event_generate("<<Copy>>")
except tk.TclError:
pass
def paste(self):
try:
self.text_widget.event_generate("<<Paste>>")
except tk.TclError:
pass
# 字體操作方法
def change_font_family(self, font):
self.current_font = font
self.text_widget.config(font=(font, self.current_size))
self.update_status(f"字體更改為: {font}")
def change_font_size(self, size):
self.current_size = size
self.text_widget.config(font=(self.current_font, size))
self.update_status(f"字號更改為: {size}pt")
def make_bold(self):
messagebox.showinfo("粗體", "文本設置為粗體")
def make_italic(self):
messagebox.showinfo("斜體", "文本設置為斜體")
# 顏色操作方法
def change_text_color(self, color):
self.current_color = color
self.text_widget.config(fg=color)
color_names = {
"black": "黑色", "red": "紅色", "green": "綠色",
"blue": "藍色", "yellow": "黃色", "purple": "紫色", "orange": "橙色"
}
self.update_status(f"文本顏色更改為: {color_names.get(color, color)}")
# 對齊操作方法
def align_left(self):
messagebox.showinfo("對齊", "文本左對齊")
def align_center(self):
messagebox.showinfo("對齊", "文本居中對齊")
def align_right(self):
messagebox.showinfo("對齊", "文本右對齊")
def align_justify(self):
messagebox.showinfo("對齊", "文本兩端對齊")
def update_status(self, message):
"""更新狀態欄"""
self.statusbar.config(
text=f"{message} | 字體: {self.current_font} {self.current_size}pt | 顏色: {self.current_color}"
)
if __name__ == "__main__":
root = tk.Tk()
app = ToolbarWithMenubuttons(root)
root.mainloop()
示例3:動態菜單系統
import tkinter as tk
from tkinter import messagebox, simpledialog
class DynamicMenubuttonSystem:
def __init__(self, root):
self.root = root
self.menubuttons = {}
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("動態菜單系統")
self.root.geometry("600x450")
# 控制面板
self.create_control_panel()
# 菜單按鈕容器
self.menu_container = tk.Frame(self.root)
self.menu_container.pack(fill="both", expand=True, padx=20, pady=20)
# 創建一些初始菜單按鈕
self.create_default_menubuttons()
def create_control_panel(self):
"""創建控制面板"""
control_frame = tk.LabelFrame(self.root, text="菜單控制", padx=10, pady=10)
control_frame.pack(fill="x", padx=10, pady=10)
# 添加菜單按鈕
add_frame = tk.Frame(control_frame)
add_frame.pack(fill="x", pady=5)
tk.Label(add_frame, text="菜單文本:").pack(side="left")
self.menu_text = tk.Entry(add_frame, width=15)
self.menu_text.pack(side="left", padx=5)
self.menu_text.insert(0, "新菜單")
tk.Button(add_frame, text="添加菜單按鈕",
command=self.add_menubutton).pack(side="left", padx=5)
# 管理菜單項
manage_frame = tk.Frame(control_frame)
manage_frame.pack(fill="x", pady=5)
tk.Label(manage_frame, text="選擇菜單:").pack(side="left")
self.menu_selector = tk.StringVar()
menu_combo = tk.Entry(manage_frame, textvariable=self.menu_selector, width=15, state="readonly")
menu_combo.pack(side="left", padx=5)
tk.Button(manage_frame, text="添加菜單項",
command=self.add_menu_item).pack(side="left", padx=5)
tk.Button(manage_frame, text="刪除菜單",
command=self.delete_menubutton).pack(side="left", padx=5)
# 狀態顯示
self.status_label = tk.Label(control_frame, text="就緒", fg="blue")
self.status_label.pack(anchor="w")
def create_default_menubuttons(self):
"""創建默認的菜單按鈕"""
default_menus = {
"文件": ["新建", "打開", "保存", "退出"],
"編輯": ["撤銷", "重做", "剪切", "複製", "粘貼"],
"視圖": ["縮放", "主題", "工具欄", "狀態欄"]
}
for menu_text, items in default_menus.items():
self.create_menubutton_with_items(menu_text, items)
self.update_menu_selector()
def create_menubutton_with_items(self, menu_text, items):
"""創建帶項目的菜單按鈕"""
menubutton = tk.Menubutton(
self.menu_container,
text=menu_text,
relief=tk.RAISED,
bg="lightblue"
)
menubutton.pack(side="left", padx=5, pady=5)
menu = tk.Menu(menubutton, tearoff=0)
menubutton.config(menu=menu)
# 添加菜單項
for item in items:
menu.add_command(
label=item,
command=lambda m=menu_text, i=item: self.menu_item_clicked(m, i)
)
# 存儲菜單引用
self.menubuttons[menu_text] = {
'widget': menubutton,
'menu': menu,
'items': items.copy()
}
def add_menubutton(self):
"""添加新的菜單按鈕"""
menu_text = self.menu_text.get().strip()
if not menu_text:
messagebox.showwarning("警告", "請輸入菜單文本")
return
if menu_text in self.menubuttons:
messagebox.showwarning("警告", "菜單已存在")
return
self.create_menubutton_with_items(menu_text, [])
self.menu_text.delete(0, "end")
self.update_menu_selector()
self.update_status(f"已添加菜單: {menu_text}")
def add_menu_item(self):
"""向選中的菜單添加項目"""
menu_text = self.menu_selector.get()
if not menu_text:
messagebox.showwarning("警告", "請先選擇菜單")
return
item_text = simpledialog.askstring("添加菜單項", "輸入菜單項文本:")
if item_text:
menu_data = self.menubuttons[menu_text]
menu_data['menu'].add_command(
label=item_text,
command=lambda m=menu_text, i=item_text: self.menu_item_clicked(m, i)
)
menu_data['items'].append(item_text)
self.update_status(f"已向 {menu_text} 添加: {item_text}")
def delete_menubutton(self):
"""刪除選中的菜單按鈕"""
menu_text = self.menu_selector.get()
if not menu_text:
messagebox.showwarning("警告", "請先選擇菜單")
return
if messagebox.askyesno("確認", f"確定要刪除菜單 '{menu_text}' 嗎?"):
# 銷燬組件
self.menubuttons[menu_text]['widget'].destroy()
# 從字典中移除
del self.menubuttons[menu_text]
# 更新選擇器
self.update_menu_selector()
self.update_status(f"已刪除菜單: {menu_text}")
def update_menu_selector(self):
"""更新菜單選擇器"""
menus = list(self.menubuttons.keys())
if menus:
self.menu_selector.set(menus[0])
else:
self.menu_selector.set("")
def menu_item_clicked(self, menu_text, item_text):
"""菜單項被點擊"""
self.update_status(f"點擊: {menu_text} -> {item_text}")
messagebox.showinfo("菜單操作", f"您點擊了: {menu_text} -> {item_text}")
def update_status(self, message):
"""更新狀態"""
self.status_label.config(text=message)
if __name__ == "__main__":
root = tk.Tk()
app = DynamicMenubuttonSystem(root)
root.mainloop()
Menubutton的主要方法和屬性
# 創建Menubutton
menubutton = tk.Menubutton(parent, **options)
# 主要配置選項
menubutton.config(
text="按鈕文本", # 顯示文本
menu=menu_object, # 關聯的Menu對象
direction="below", # 菜單彈出方向: above, below, left, right
relief=tk.RAISED, # 邊框樣式
state="normal", # 狀態: normal, disabled, active
bg="color", # 背景色
fg="color", # 前景色
font=("Arial", 10), # 字體
padx=10, # 水平內邊距
pady=5, # 垂直內邊距
compound="left" # 圖文相對位置
)
# 主要方法
menubutton.cget(option) # 獲取配置值
menubutton.config(**options) # 重新配置
menubutton.invoke() # 模擬點擊(觸發關聯動作)
# 綁定事件
menubutton.bind("<Button-1>", callback) # 鼠標點擊事件
使用場景總結
- 工具欄菜單:在工具欄中提供功能分組
- 導航菜單:網站或應用程序的導航菜單
- 選項選擇:顏色選擇、字體選擇、大小選擇等
- 動態菜單:根據上下文動態變化的菜單
- 緊湊界面:在有限空間內提供多個選項
- 自定義控件:創建特殊的自定義界面控件
Menubutton組件提供了創建下拉菜單的靈活方式,特別適合在工具欄、導航欄等需要節省空間的地方使用。它與Menu組件的結合使用可以創建出功能豐富、用户友好的界面。