Frame(框架)是Tkinter中最常用的容器組件,用於組織和分組其他組件。
基本用法
1. 導入和基本創建
import tkinter as tk
from tkinter import ttk
# 創建主窗口
root = tk.Tk()
root.title("Frame組件詳解")
root.geometry("600x400")
2. 創建基本Frame
# 創建Frame
frame = tk.Frame(root, bg="lightblue", relief=tk.RAISED, bd=2)
frame.pack(pady=20, padx=20, fill=tk.BOTH, expand=True)
# 在Frame中添加組件
label = tk.Label(frame, text="這是一個Frame中的標籤", bg="lightblue")
label.pack(pady=10)
button = tk.Button(frame, text="Frame中的按鈕")
button.pack(pady=10)
root.mainloop()
Frame的完整參數和功能
示例1:Frame的全面展示
python
import tkinter as tk
from tkinter import ttk
class FrameComprehensive:
def __init__(self, root):
self.root = root
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("Frame組件全面展示")
self.root.geometry("700x600")
# 創建主Frame
main_frame = tk.Frame(self.root, bg="#f0f0f0")
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 1. 基本Frame示例
self.create_basic_frames(main_frame)
# 2. 邊框樣式示例
self.create_border_styles(main_frame)
# 3. 佈局管理示例
self.create_layout_examples(main_frame)
# 4. 嵌套Frame示例
self.create_nested_frames(main_frame)
def create_basic_frames(self, parent):
"""創建基本Frame示例"""
section_frame = tk.LabelFrame(parent, text="1. 基本Frame示例", padx=10, pady=10)
section_frame.pack(fill=tk.X, padx=5, pady=5)
# 普通Frame
normal_frame = tk.Frame(section_frame, bg="lightyellow", height=80)
normal_frame.pack(fill=tk.X, pady=5)
tk.Label(normal_frame, text="普通Frame", bg="lightyellow").pack(pady=10)
# 帶邊框的Frame
bordered_frame = tk.Frame(
section_frame,
bg="lightgreen",
relief=tk.GROOVE,
bd=3,
height=80
)
bordered_frame.pack(fill=tk.X, pady=5)
tk.Label(bordered_frame, text="帶邊框的Frame", bg="lightgreen").pack(pady=10)
def create_border_styles(self, parent):
"""創建邊框樣式示例"""
section_frame = tk.LabelFrame(parent, text="2. 邊框樣式示例", padx=10, pady=10)
section_frame.pack(fill=tk.X, padx=5, pady=5)
border_styles = [
("FLAT", tk.FLAT),
("RAISED", tk.RAISED),
("SUNKEN", tk.SUNKEN),
("GROOVE", tk.GROOVE),
("RIDGE", tk.RIDGE)
]
for style_name, style in border_styles:
frame = tk.Frame(
section_frame,
relief=style,
bd=3,
height=60,
bg="#e0e0e0"
)
frame.pack(fill=tk.X, pady=2)
tk.Label(frame, text=f"邊框樣式: {style_name}", bg="#e0e0e0").pack(pady=10)
def create_layout_examples(self, parent):
"""創建佈局管理示例"""
section_frame = tk.LabelFrame(parent, text="3. 佈局管理示例", padx=10, pady=10)
section_frame.pack(fill=tk.X, padx=5, pady=5)
# pack佈局
pack_frame = tk.Frame(section_frame, bg="lightblue", height=80)
pack_frame.pack(fill=tk.X, pady=5)
tk.Label(pack_frame, text="pack佈局", bg="lightblue").pack(side=tk.LEFT, padx=10)
for i in range(3):
tk.Button(pack_frame, text=f"按鈕{i+1}").pack(side=tk.LEFT, padx=5)
# grid佈局
grid_frame = tk.Frame(section_frame, bg="lightcoral", height=80)
grid_frame.pack(fill=tk.X, pady=5)
tk.Label(grid_frame, text="grid佈局", bg="lightcoral").grid(row=0, column=0, padx=10)
for i in range(3):
tk.Button(grid_frame, text=f"按鈕{i+1}").grid(row=0, column=i+1, padx=5)
# place佈局
place_frame = tk.Frame(section_frame, bg="lightgreen", height=80)
place_frame.pack(fill=tk.X, pady=5)
tk.Label(place_frame, text="place佈局", bg="lightgreen").place(x=10, y=10)
for i in range(3):
tk.Button(place_frame, text=f"按鈕{i+1}").place(x=100 + i*80, y=10)
def create_nested_frames(self, parent):
"""創建嵌套Frame示例"""
section_frame = tk.LabelFrame(parent, text="4. 嵌套Frame示例", padx=10, pady=10)
section_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 創建外層Frame
outer_frame = tk.Frame(section_frame, bg="navy", relief=tk.RAISED, bd=2)
outer_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
tk.Label(outer_frame, text="外層Frame", bg="navy", fg="white",
font=("Arial", 12, "bold")).pack(pady=5)
# 創建內層Frame容器
inner_container = tk.Frame(outer_frame, bg="navy")
inner_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 創建三個內層Frame
inner_frames = []
colors = ["red", "green", "blue"]
for i, color in enumerate(colors):
inner_frame = tk.Frame(
inner_container,
bg=color,
relief=tk.SUNKEN,
bd=2,
width=150,
height=100
)
inner_frame.pack(side=tk.LEFT, padx=10, pady=10, fill=tk.BOTH, expand=True)
inner_frame.pack_propagate(False) # 防止Frame收縮
tk.Label(inner_frame, text=f"內層Frame {i+1}",
bg=color, fg="white", font=("Arial", 10, "bold")).pack(pady=10)
# 在內層Frame中添加按鈕
for j in range(2):
tk.Button(inner_frame, text=f"按鈕{j+1}").pack(pady=2)
inner_frames.append(inner_frame)
if __name__ == "__main__":
root = tk.Tk()
app = FrameComprehensive(root)
root.mainloop()
實際應用示例
示例2:用户註冊表單
import tkinter as tk
from tkinter import messagebox, ttk
class RegistrationForm:
def __init__(self, root):
self.root = root
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("用户註冊表單 - Frame示例")
self.root.geometry("500x600")
self.root.resizable(False, False)
# 創建主Frame
main_frame = tk.Frame(self.root, bg="#f5f5f5", padx=20, pady=20)
main_frame.pack(fill=tk.BOTH, expand=True)
# 標題
title_frame = tk.Frame(main_frame, bg="#f5f5f5")
title_frame.pack(fill=tk.X, pady=(0, 20))
tk.Label(title_frame, text="用户註冊",
font=("Arial", 18, "bold"), bg="#f5f5f5", fg="#333").pack()
# 表單Frame
form_frame = tk.Frame(main_frame, bg="white", relief=tk.GROOVE, bd=1)
form_frame.pack(fill=tk.BOTH, expand=True)
# 個人信息部分
self.create_personal_info_section(form_frame)
# 賬户信息部分
self.create_account_info_section(form_frame)
# 按鈕部分
self.create_button_section(form_frame)
def create_personal_info_section(self, parent):
"""創建個人信息部分"""
# 分組Frame
personal_frame = tk.LabelFrame(parent, text="個人信息",
font=("Arial", 10, "bold"),
padx=15, pady=15, bg="white")
personal_frame.pack(fill=tk.X, padx=10, pady=10)
# 姓名行
name_frame = tk.Frame(personal_frame, bg="white")
name_frame.pack(fill=tk.X, pady=5)
tk.Label(name_frame, text="姓名:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.name_entry = tk.Entry(name_frame, width=30)
self.name_entry.pack(side=tk.LEFT, padx=5)
# 性別行
gender_frame = tk.Frame(personal_frame, bg="white")
gender_frame.pack(fill=tk.X, pady=5)
tk.Label(gender_frame, text="性別:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.gender_var = tk.StringVar(value="male")
male_radio = tk.Radiobutton(gender_frame, text="男", variable=self.gender_var,
value="male", bg="white")
male_radio.pack(side=tk.LEFT, padx=5)
female_radio = tk.Radiobutton(gender_frame, text="女", variable=self.gender_var,
value="female", bg="white")
female_radio.pack(side=tk.LEFT, padx=5)
# 生日行
birthday_frame = tk.Frame(personal_frame, bg="white")
birthday_frame.pack(fill=tk.X, pady=5)
tk.Label(birthday_frame, text="生日:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
# 年月日選擇
year_frame = tk.Frame(birthday_frame, bg="white")
year_frame.pack(side=tk.LEFT, padx=5)
tk.Label(year_frame, text="年", bg="white", font=("Arial", 8)).pack(side=tk.RIGHT)
self.year_combo = ttk.Combobox(year_frame, width=5, values=[str(i) for i in range(1950, 2024)])
self.year_combo.pack(side=tk.LEFT)
month_frame = tk.Frame(birthday_frame, bg="white")
month_frame.pack(side=tk.LEFT, padx=5)
tk.Label(month_frame, text="月", bg="white", font=("Arial", 8)).pack(side=tk.RIGHT)
self.month_combo = ttk.Combobox(month_frame, width=3,
values=[f"{i:02d}" for i in range(1, 13)])
self.month_combo.pack(side=tk.LEFT)
day_frame = tk.Frame(birthday_frame, bg="white")
day_frame.pack(side=tk.LEFT, padx=5)
tk.Label(day_frame, text="日", bg="white", font=("Arial", 8)).pack(side=tk.RIGHT)
self.day_combo = ttk.Combobox(day_frame, width=3,
values=[f"{i:02d}" for i in range(1, 32)])
self.day_combo.pack(side=tk.LEFT)
# 聯繫電話
phone_frame = tk.Frame(personal_frame, bg="white")
phone_frame.pack(fill=tk.X, pady=5)
tk.Label(phone_frame, text="聯繫電話:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.phone_entry = tk.Entry(phone_frame, width=30)
self.phone_entry.pack(side=tk.LEFT, padx=5)
def create_account_info_section(self, parent):
"""創建賬户信息部分"""
# 分組Frame
account_frame = tk.LabelFrame(parent, text="賬户信息",
font=("Arial", 10, "bold"),
padx=15, pady=15, bg="white")
account_frame.pack(fill=tk.X, padx=10, pady=10)
# 用户名
username_frame = tk.Frame(account_frame, bg="white")
username_frame.pack(fill=tk.X, pady=5)
tk.Label(username_frame, text="用户名:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.username_entry = tk.Entry(username_frame, width=30)
self.username_entry.pack(side=tk.LEFT, padx=5)
# 密碼
password_frame = tk.Frame(account_frame, bg="white")
password_frame.pack(fill=tk.X, pady=5)
tk.Label(password_frame, text="密碼:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.password_entry = tk.Entry(password_frame, width=30, show="*")
self.password_entry.pack(side=tk.LEFT, padx=5)
# 確認密碼
confirm_frame = tk.Frame(account_frame, bg="white")
confirm_frame.pack(fill=tk.X, pady=5)
tk.Label(confirm_frame, text="確認密碼:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.confirm_entry = tk.Entry(confirm_frame, width=30, show="*")
self.confirm_entry.pack(side=tk.LEFT, padx=5)
# 郵箱
email_frame = tk.Frame(account_frame, bg="white")
email_frame.pack(fill=tk.X, pady=5)
tk.Label(email_frame, text="郵箱:", bg="white", width=10, anchor="e").pack(side=tk.LEFT)
self.email_entry = tk.Entry(email_frame, width=30)
self.email_entry.pack(side=tk.LEFT, padx=5)
def create_button_section(self, parent):
"""創建按鈕部分"""
button_frame = tk.Frame(parent, bg="white", pady=20)
button_frame.pack(fill=tk.X, padx=10)
# 註冊按鈕
register_btn = tk.Button(button_frame, text="註冊",
bg="#4CAF50", fg="white", font=("Arial", 12),
width=15, command=self.register)
register_btn.pack(side=tk.LEFT, padx=20)
# 重置按鈕
reset_btn = tk.Button(button_frame, text="重置",
bg="#f44336", fg="white", font=("Arial", 12),
width=15, command=self.reset_form)
reset_btn.pack(side=tk.RIGHT, padx=20)
def register(self):
"""註冊按鈕點擊事件"""
# 簡單的表單驗證
if not self.name_entry.get().strip():
messagebox.showerror("錯誤", "請輸入姓名")
return
if not self.username_entry.get().strip():
messagebox.showerror("錯誤", "請輸入用户名")
return
if not self.password_entry.get():
messagebox.showerror("錯誤", "請輸入密碼")
return
if self.password_entry.get() != self.confirm_entry.get():
messagebox.showerror("錯誤", "密碼不一致")
return
# 顯示註冊信息
info = f"""
註冊信息:
姓名: {self.name_entry.get()}
性別: {'男' if self.gender_var.get() == 'male' else '女'}
用户名: {self.username_entry.get()}
郵箱: {self.email_entry.get()}
電話: {self.phone_entry.get()}
"""
messagebox.showinfo("註冊成功", info)
def reset_form(self):
"""重置表單"""
self.name_entry.delete(0, tk.END)
self.username_entry.delete(0, tk.END)
self.password_entry.delete(0, tk.END)
self.confirm_entry.delete(0, tk.END)
self.email_entry.delete(0, tk.END)
self.phone_entry.delete(0, tk.END)
self.gender_var.set("male")
self.year_combo.set("")
self.month_combo.set("")
self.day_combo.set("")
if __name__ == "__main__":
root = tk.Tk()
app = RegistrationForm(root)
root.mainloop()
示例3:儀表板界面
import tkinter as tk
from tkinter import ttk
import random
class Dashboard:
def __init__(self, root):
self.root = root
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("儀表板界面 - Frame示例")
self.root.geometry("900x700")
# 創建主容器
main_container = tk.Frame(self.root, bg="#2c3e50")
main_container.pack(fill=tk.BOTH, expand=True)
# 頂部導航欄
self.create_navbar(main_container)
# 主要內容區域
content_frame = tk.Frame(main_container, bg="#ecf0f1")
content_frame.pack(fill=tk.BOTH, expand=True)
# 側邊欄
self.create_sidebar(content_frame)
# 主內容區域
self.create_main_content(content_frame)
def create_navbar(self, parent):
"""創建頂部導航欄"""
navbar = tk.Frame(parent, bg="#34495e", height=60)
navbar.pack(fill=tk.X)
navbar.pack_propagate(False)
# logo和標題
logo_frame = tk.Frame(navbar, bg="#34495e")
logo_frame.pack(side=tk.LEFT, padx=20)
tk.Label(logo_frame, text="🚀", font=("Arial", 20), bg="#34495e", fg="white").pack(side=tk.LEFT)
tk.Label(logo_frame, text="我的儀表板", font=("Arial", 16, "bold"),
bg="#34495e", fg="white").pack(side=tk.LEFT, padx=10)
# 導航菜單
nav_menu_e = tk.Frame(navbar, bg="#34495e")
nav_menu_e.pack(side=tk.RIGHT, padx=20)
nav_items = ["首頁", "分析", "報告", "設置"]
for item in nav_items:
btn = tk.Button(nav_menu, text=item, bg="#3498db", fg="white",
relief=tk.FLAT, padx=15, pady=5,
command=lambda i=item: self.nav_item_click(i))
btn.pack(side=tk.LEFT, padx=5)
# 用户信息
user_frame = tk.Frame(navbar, bg="#34495e")
user_frame.pack(side=tk.RIGHT, padx=20)
tk.Label(user_frame, text="👤 管理員", font=("Arial", 10),
bg="#34495e", fg="white").pack(side=tk.LEFT, padx=10)
def create_sidebar(self, parent):
"""創建側邊欄"""
sidebar = tk.Frame(parent, bg="#34495e", width=200)
sidebar.pack(side=tk.LEFT, fill=tk.Y)
sidebar.pack_propagate(False)
# 側邊欄標題
tk.Label(sidebar, text="功能菜單", font=("Arial", 12, "bold"),
bg="#34495e", fg="white", pady=15).pack(fill=tk.X)
# 菜單項
menu_items = [
("📊 數據概覽", "overview"),
("📈 性能指標", "metrics"),
("👥 用户管理", "users"),
("💰 財務管理", "finance"),
("⚙️ 系統設置", "settings"),
("🔒 安全中心", "security"),
("📋 日誌查看", "logs"),
("🆘 幫助支持", "help")
]
for text, command in menu_items:
btn = tk.Button(sidebar, text=text, anchor="w", font=("Arial", 10),
bg="#34495e", fg="#bdc3c7", relief=tk.FLAT,
command=lambda c=command: self.menu_item_click(c))
btn.pack(fill=tk.X, padx=10, pady=2)
def create_main_content(self, parent):
"""創建主內容區域"""
main_content = tk.Frame(parent, bg="#ecf0f1")
main_content.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 歡迎橫幅
banner_frame = tk.Frame(main_content, bg="#3498db", height=120)
banner_frame.pack(fill=tk.X, padx=20, pady=20)
banner_frame.pack_propagate(False)
tk.Label(banner_frame, text="歡迎回來,管理員!",
font=("Arial", 20, "bold"), bg="#3498db", fg="white").pack(expand=True)
tk.Label(banner_frame, text="今天是美好的一天,繼續努力!",
font=("Arial", 12), bg="#3498db", fg="#ecf0f1").pack(pady=(0, 20))
# 指標卡片區域
self.create_metrics_cards(main_content)
# 圖表區域
self.create_charts_area(main_content)
def create_metrics_cards(self, parent):
"""創建指標卡片"""
cards_frame = tk.Frame(parent, bg="#ecf0f1")
cards_frame.pack(fill=tk.X, padx=20, pady=10)
metrics = [
{"title": "總用户數", "value": "1,234", "change": "+12%", "color": "#e74c3c", "icon": "👥"},
{"title": "總收入", "value": "¥45,678", "change": "+8%", "color": "#2ecc71", "icon": "💰"},
{"title": "訂單數", "value": "567", "change": "+15%", "color": "#3498db", "icon": "📦"},
{"title": "滿意度", "value": "98%", "change": "+2%", "color": "#9b59b6", "icon": "⭐"}
]
for i, metric in enumerate(metrics):
card = tk.Frame(cards_frame, bg="white", relief=tk.RAISED, bd=1)
card.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)
# 卡片內容
icon_frame = tk.Frame(card, bg=metric["color"], height=40)
icon_frame.pack(fill=tk.X)
icon_frame.pack_propagate(False)
tk.Label(icon_frame, text=metric["icon"], font=("Arial", 16),
bg=metric["color"], fg="white").pack(expand=True)
content_frame = tk.Frame(card, bg="white", padx=10, pady=10)
content_frame.pack(fill=tk.BOTH, expand=True)
tk.Label(content_frame, text=metric["title"], font=("Arial", 10, "bold"),
bg="white", fg="#7f8c8d").pack(anchor="w")
tk.Label(content_frame, text=metric["value"], font=("Arial", 18, "bold"),
bg="white", fg="#2c3e50").pack(anchor="w", pady=(5, 0))
change_color = "#2ecc71" if metric["change"].startswith("+") else "#e74c3c"
tk.Label(content_frame, text=metric["change"], font=("Arial", 10),
bg="white", fg=change_color).pack(anchor="w")
def create_charts_area(self, parent):
"""創建圖表區域"""
charts_frame = tk.Frame(parent, bg="#ecf0f1")
charts_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# 左側圖表
left_chart = tk.Frame(charts_frame, bg="white", relief=tk.GROOVE, bd=1)
left_chart.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
tk.Label(left_chart, text="📈 銷售趨勢", font=("Arial", 12, "bold"),
bg="white", pady=10).pack()
# 模擬圖表
chart_canvas_e = tk.Canvas(left_chart, bg="white", height=200)
chart_canvas_e.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.draw_simple_chart(chart_canvas)
# 右側圖表
right_chart = tk.Frame(charts_frame, bg="white", relief=tk.GROOVE, bd=1)
right_chart.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(10, 0))
tk.Label(right_chart, text="🍩 用户分佈", font=("Arial", 12, "bold"),
bg="white", pady=10).pack()
# 模擬餅圖
pie_canvas_e = tk.Canvas(right_chart, bg="white", height=200)
pie_canvas_e.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.draw_simple_pie(pie_canvas)
def draw_simple_chart(self, canvas):
"""繪製簡單折線圖"""
width = canvas.winfo_width() or 300
height = canvas.winfo_height() or 200
points = []
for i in range(10):
x = 30 + i * (width - 60) / 9
y = height - 30 - random.randint(20, height - 60)
points.extend([x, y])
if points:
canvas.create_line(points, fill="#3498db", width=2, smooth=True)
def draw_simple_pie(self, canvas):
"""繪製簡單餅圖"""
width = canvas.winfo_width() or 300
height = canvas.winfo_height() or 200
colors = ["#e74c3c", "#3498db", "#2ecc71", "#f39c12"]
for i, color in enumerate(colors):
canvas.create_oval(50 + i*20, 50 + i*10, 150 + i*20, 150 + i*10,
fill=color, outline="")
def nav_item_click(self, item):
"""導航項點擊事件"""
print(f"導航菜單點擊: {item}")
def menu_item_click(self, command):
"""側邊欄菜單點擊事件"""
print(f"菜單點擊: {command}")
if __name__ == "__main__":
root = tk.Tk()
app = Dashboard(root)
root.mainloop()
Frame的主要方法和屬性
# 創建Frame
frame = tk.Frame(parent, **options)
# 主要配置選項
frame.config(
bg="color", # 背景色
bd=2, # 邊框寬度
relief=tk.RAISED, # 邊框樣式: FLAT, RAISED, SUNKEN, GROOVE, RIDGE
padx=10, # 水平內邊距
pady=10, # 垂直內邊距
width=200, # 寬度
height=150, # 高度
cursor="hand2", # 鼠標指針樣式
takefocus=True # 是否可獲取焦點
)
# 佈局方法
frame.pack(**options) # pack佈局
frame.grid(**options) # grid佈局
frame.place(**options) # place佈局
# 其他方法
frame.pack_propagate(False) # 阻止自動調整大小
frame.winfo_children() # 獲取所有子組件
frame.lift() # 提升到頂層
frame.lower() # 降低到底層
# 事件綁定
frame.bind("<Button-1>", callback) # 鼠標點擊事件
使用場景總結
- 表單組織:分組相關的表單字段
- 佈局管理:使用Frame創建複雜的佈局結構
- 組件分組:將功能相關的組件組織在一起
- 標籤頁內容:作為Notebook標籤頁的容器
- 工具欄:創建工具欄和狀態欄
- 卡片式設計:創建現代化的卡片式界面
- 嵌套佈局:構建複雜的多層級界面
Frame是Tkinter中最基礎也是最重要的容器組件,它提供了組織和結構化用户界面的能力,是構建複雜GUI應用程序的基石。