Widget(組件)是Tkinter中構建用户界面的基本元素。以下是Tkinter中所有主要Widget的全面詳解。
基本概念
Widget是Tkinter中所有可視化組件的基類,提供了通用的功能和屬性。
導入和基本使用
import tkinter as tk
from tkinter import ttk, messagebox
# 創建主窗口
root = tk.Tk()
root.title("Tkinter Widget詳解")
root.geometry("800x600")
基礎Widget類
示例1:Widget基礎屬性和方法
import tkinter as tk
from tkinter import ttk
class WidgetBasics:
def __init__(self, root):
self.root = root
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("Widget基礎")
# 創建主Frame
main_frame = ttk.Frame(self.root, padding=20)
main_frame.pack(fill=tk.BOTH, expand=True)
# 標題
title_label = ttk.Label(main_frame, text="Widget基礎屬性和方法",
font=("Arial", 16, "bold"))
title_label.pack(pady=(0, 20))
# 1. 基本Widget操作
self.create_basic_widget_section(main_frame)
# 2. 幾何管理
self.create_geometry_section(main_frame)
# 3. 事件處理
self.create_event_section(main_frame)
# 4. 狀態管理
self.create_state_section(main_frame)
def create_basic_widget_section(self, parent):
"""創建基本Widget操作部分"""
section_frame = ttk.LabelFrame(parent, text="1. 基本Widget操作", padding=10)
section_frame.pack(fill=tk.X, pady=10)
# 創建一些基本Widget
button = ttk.Button(section_frame, text="測試按鈕")
button.pack(side=tk.LEFT, padx=5)
entry = ttk.Entry(section_frame)
entry.pack(side=tk.LEFT, padx=5)
entry.insert(0, "輸入文本")
checkbutton = ttk.Checkbutton(section_frame, text="複選框")
checkbutton.pack(side=tk.LEFT, padx=5)
# Widget信息顯示
info_frame = ttk.Frame(section_frame)
info_frame.pack(side=tk.LEFT, padx=20)
self.info_label = ttk.Label(info_frame, text="選擇Widget查看信息")
self.info_label.pack()
# 綁定點擊事件顯示信息
widgets = [button, entry, checkbutton]
for widget in widgets:
widget.bind('<Button-1>', lambda e, w=widget: self.show_widget_info(w))
def create_geometry_section(self, parent):
"""創建幾何管理部分"""
section_frame = ttk.LabelFrame(parent, text="2. 幾何管理", padding=10)
section_frame.pack(fill=tk.X, pady=10)
# 創建測試Widget
test_frame = ttk.Frame(section_frame, height=100, relief='solid')
test_frame.pack(fill=tk.X, pady=5)
test_frame.pack_propagate(False) # 防止Frame收縮
self.test_label = ttk.Label(test_frame, text="測試標籤", background='lightblue')
self.test_label.pack(pady=20)
# 幾何控制按鈕
control_frame = ttk.Frame(section_frame)
control_frame.pack(fill=tk.X, pady=5)
geometry_buttons = [
("獲取位置", self.get_position),
("獲取大小", self.get_size),
("移動到(10,10)", lambda: self.move_widget(10, 10)),
("移動到中心", self.move_to_center),
("改變大小", self.resize_widget)
]
for text, command in geometry_buttons:
ttk.Button(control_frame, text=text, command=command).pack(side=tk.LEFT, padx=2)
def create_event_section(self, parent):
"""創建事件處理部分"""
section_frame = ttk.LabelFrame(parent, text="3. 事件處理", padding=10)
section_frame.pack(fill=tk.X, pady=10)
# 事件測試Widget
event_frame = ttk.Frame(section_frame)
event_frame.pack(fill=tk.X, pady=5)
self.event_button = ttk.Button(event_frame, text="事件測試按鈕")
self.event_button.pack(side=tk.LEFT, padx=5)
self.event_entry = ttk.Entry(event_frame)
self.event_entry.pack(side=tk.LEFT, padx=5)
# 事件日誌
self.event_log = tk.Text(section_frame, height=4, width=50)
self.event_log.pack(fill=tk.X, pady=5)
# 綁定事件
self.bind_events()
def create_state_section(self, parent):
"""創建狀態管理部分"""
section_frame = ttk.LabelFrame(parent, text="4. 狀態管理", padding=10)
section_frame.pack(fill=tk.X, pady=10)
# 狀態測試Widget
state_frame = ttk.Frame(section_frame)
state_frame.pack(fill=tk.X, pady=5)
self.state_button = ttk.Button(state_frame, text="狀態測試按鈕")
self.state_button.pack(side=tk.LEFT, padx=5)
# 狀態控制
control_frame = ttk.Frame(section_frame)
control_frame.pack(fill=tk.X, pady=5)
state_buttons = [
("正常", lambda: self.set_widget_state('normal')),
("禁用", lambda: self.set_widget_state('disabled')),
("只讀", lambda: self.set_widget_state('readonly')),
("獲取狀態", self.get_widget_state)
]
for text, command in state_buttons:
ttk.Button(control_frame, text=text, command=command).pack(side=tk.LEFT, padx=2)
def show_widget_info(self, widget):
"""顯示Widget信息"""
info = f"""
Widget類型: {type(widget).__name__}
Widget ID: {str(widget)}
類: {widget.winfo_class()}
父級: {widget.winfo_parent()}
子級數量: {len(widget.winfo_children())}
"""
self.info_label.config(text=info)
def get_position(self):
"""獲取Widget位置"""
x = self.test_label.winfo_x()
y = self.test_label.winfo_y()
self.log_event(f"標籤位置: x={x}, y={y}")
def get_size(self):
"""獲取Widget大小"""
width = self.test_label.winfo_width()
height = self.test_label.winfo_height()
self.log_event(f"標籤大小: {width}x{height}")
def move_widget(self, x, y):
"""移動Widget"""
self.test_label.place(x=x, y=y)
self.log_event(f"移動到: ({x}, {y})")
def move_to_center(self):
"""移動到中心"""
self.test_label.place(relx=0.5, rely=0.5, anchor='center')
self.log_event("移動到中心")
def resize_widget(self):
"""改變大小"""
self.test_label.config(text="更大的標籤")
self.log_event("大小已改變")
def bind_events(self):
"""綁定事件"""
# 按鈕事件
self.event_button.bind('<Button-1>', lambda e: self.log_event("按鈕點擊"))
self.event_button.bind('<Enter>', lambda e: self.log_event("鼠標進入按鈕"))
self.event_button.bind('<Leave>', lambda e: self.log_event("鼠標離開按鈕"))
# 輸入框事件
self.event_entry.bind('<FocusIn>', lambda e: self.log_event("輸入框獲得焦點"))
self.event_entry.bind('<FocusOut>', lambda e: self.log_event("輸入框失去焦點"))
self.event_entry.bind('<KeyPress>', lambda e: self.log_event(f"按鍵: {e.keysym}"))
def set_widget_state(self, state):
"""設置Widget狀態"""
self.state_button.config(state=state)
self.log_event(f"按鈕狀態設置為: {state}")
def get_widget_state(self):
"""獲取Widget狀態"""
state = self.state_button.cget('state')
self.log_event(f"按鈕狀態: {state}")
def log_event(self, message):
"""記錄事件"""
self.event_log.insert(tk.END, f"{message}\n")
self.event_log.see(tk.END)
if __name__ == "__main__":
root = tk.Tk()
app = WidgetBasics(root)
root.mainloop()
完整Widget分類展示
示例2:Widget大全
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
from tkinter import colorchooser, filedialog
import datetime
class WidgetGallery:
def __init__(self, root):
self.root = root
self.setup_ui()
def setup_ui(self):
"""設置用户界面"""
self.root.title("Tkinter Widget大全")
self.root.geometry("1000x800")
# 創建主容器
main_container = ttk.Frame(self.root)
main_container.pack(fill=tk.BOTH, expand=True)
# 創建Notebook
notebook = ttk.Notebook(main_container)
notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 基本Widget標籤頁
self.create_basic_widgets_tab(notebook)
# 輸入Widget標籤頁
self.create_input_widgets_tab(notebook)
# 選擇Widget標籤頁
self.create_selection_widgets_tab(notebook)
# 容器Widget標籤頁
self.create_container_widgets_tab(notebook)
# 高級Widget標籤頁
self.create_advanced_widgets_tab(notebook)
def create_basic_widgets_tab(self, notebook):
"""創建基本Widget標籤頁"""
frame = ttk.Frame(notebook, padding=15)
notebook.add(frame, text="基本Widget")
# Label
label_frame = ttk.LabelFrame(frame, text="Label 標籤", padding=10)
label_frame.pack(fill=tk.X, pady=5)
ttk.Label(label_frame, text="普通標籤").pack(side=tk.LEFT, padx=5)
ttk.Label(label_frame, text="帶樣式的標籤", foreground="blue",
font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=5)
ttk.Label(label_frame, text="圖片標籤").pack(side=tk.LEFT, padx=5)
# Button
button_frame = ttk.LabelFrame(frame, text="Button 按鈕", padding=10)
button_frame.pack(fill=tk.X, pady=5)
ttk.Button(button_frame, text="普通按鈕",
command=lambda: self.show_message("按鈕點擊")).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="禁用按鈕",
state="disabled").pack(side=tk.LEFT, padx=5)
# Frame
frame_frame = ttk.LabelFrame(frame, text="Frame 框架", padding=10)
frame_frame.pack(fill=tk.X, pady=5)
inner_frame = ttk.Frame(frame_frame, relief="solid", borderwidth=1)
inner_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(inner_frame, text="內部框架內容").pack(pady=10)
def create_input_widgets_tab(self, notebook):
"""創建輸入Widget標籤頁"""
frame = ttk.Frame(notebook, padding=15)
notebook.add(frame, text="輸入Widget")
# Entry
entry_frame = ttk.LabelFrame(frame, text="Entry 輸入框", padding=10)
entry_frame.pack(fill=tk.X, pady=5)
ttk.Label(entry_frame, text="普通輸入框:").pack(side=tk.LEFT)
ttk.Entry(entry_frame).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
# 密碼輸入框
ttk.Label(entry_frame, text="密碼輸入框:").pack(side=tk.LEFT, padx=(20,0))
ttk.Entry(entry_frame, show="*").pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
# Text
text_frame = ttk.LabelFrame(frame, text="Text 文本框", padding=10)
text_frame.pack(fill=tk.BOTH, expand=True, pady=5)
text_widget = scrolledtext.ScrolledText(text_frame, height=8)
text_widget.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
text_widget.insert(tk.END, "這是一個多行文本框...\n可以輸入大量文本。")
# Spinbox
spinbox_frame = ttk.LabelFrame(frame, text="Spinbox 數字輸入框", padding=10)
spinbox_frame.pack(fill=tk.X, pady=5)
ttk.Label(spinbox_frame, text="數字選擇:").pack(side=tk.LEFT)
ttk.Spinbox(spinbox_frame, from_=0, to=100, increment=1).pack(side=tk.LEFT, padx=5)
# Scale
scale_frame = ttk.LabelFrame(frame, text="Scale 滑塊", padding=10)
scale_frame.pack(fill=tk.X, pady=5)
self.scale_var = tk.IntVar(value=50)
ttk.Scale(scale_frame, from_=0, to=100, variable=self.scale_var,
orient=tk.HORIZONTAL).pack(fill=tk.X, padx=5)
ttk.Label(scale_frame, textvariable=self.scale_var).pack()
def create_selection_widgets_tab(self, notebook):
"""創建選擇Widget標籤頁"""
frame = ttk.Frame(notebook, padding=15)
notebook.add(frame, text="選擇Widget")
# Checkbutton
check_frame = ttk.LabelFrame(frame, text="Checkbutton 複選框", padding=10)
check_frame.pack(fill=tk.X, pady=5)
self.check_var1 = tk.BooleanVar()
self.check_var2 = tk.BooleanVar(value=True)
self.check_var3 = tk.BooleanVar()
ttk.Checkbutton(check_frame, text="選項1", variable=self.check_var1).pack(side=tk.LEFT, padx=5)
ttk.Checkbutton(check_frame, text="選項2", variable=self.check_var2).pack(side=tk.LEFT, padx=5)
ttk.Checkbutton(check_frame, text="選項3", variable=self.check_var3).pack(side=tk.LEFT, padx=5)
# Radiobutton
radio_frame = ttk.LabelFrame(frame, text="Radiobutton 單選按鈕", padding=10)
radio_frame.pack(fill=tk.X, pady=5)
self.radio_var = tk.StringVar(value="A")
ttk.Radiobutton(radio_frame, text="選項A", variable=self.radio_var,
value="A").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(radio_frame, text="選項B", variable=self.radio_var,
value="B").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(radio_frame, text="選項C", variable=self.radio_var,
value="C").pack(side=tk.LEFT, padx=5)
# Listbox
listbox_frame = ttk.LabelFrame(frame, text="Listbox 列表框", padding=10)
listbox_frame.pack(fill=tk.BOTH, expand=True, pady=5)
listbox_container = ttk.Frame(listbox_frame)
listbox_container.pack(fill=tk.BOTH, expand=True)
listbox = tk.Listbox(listbox_container)
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 添加滾動條
scrollbar = ttk.Scrollbar(listbox_container, orient=tk.VERTICAL, command=listbox.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
listbox.config(yscrollcommand=scrollbar.set)
# 添加示例數據
for i in range(1, 21):
listbox.insert(tk.END, f"列表項 {i}")
# Combobox
combo_frame = ttk.LabelFrame(frame, text="Combobox 組合框", padding=10)
combo_frame.pack(fill=tk.X, pady=5)
self.combo_var = tk.StringVar()
combo = ttk.Combobox(combo_frame, textvariable=self.combo_var,
values=["Python", "Java", "JavaScript", "C++", "Go"])
combo.set("選擇編程語言")
combo.pack(fill=tk.X, padx=5)
def create_container_widgets_tab(self, notebook):
"""創建容器Widget標籤頁"""
frame = ttk.Frame(notebook, padding=15)
notebook.add(frame, text="容器Widget")
# LabelFrame
labelframe = ttk.LabelFrame(frame, text="LabelFrame 帶標籤框架", padding=10)
labelframe.pack(fill=tk.X, pady=5)
ttk.Label(labelframe, text="這是一個LabelFrame的內容").pack(pady=5)
ttk.Button(labelframe, text="框架內按鈕").pack(pady=5)
# PanedWindow
paned_frame = ttk.LabelFrame(frame, text="PanedWindow 可調整面板", padding=10)
paned_frame.pack(fill=tk.BOTH, expand=True, pady=5)
paned = ttk.PanedWindow(paned_frame, orient=tk.HORIZONTAL)
paned.pack(fill=tk.BOTH, expand=True)
left_pane = ttk.Frame(paned, relief="sunken", borderwidth=1)
right_pane = ttk.Frame(paned, relief="sunken", borderwidth=1)
ttk.Label(left_pane, text="左側面板").pack(pady=20)
ttk.Label(right_pane, text="右側面板").pack(pady=20)
paned.add(left_pane, weight=1)
paned.add(right_pane, weight=1)
# Notebook
notebook_frame = ttk.LabelFrame(frame, text="Notebook 標籤頁", padding=10)
notebook_frame.pack(fill=tk.X, pady=5)
inner_notebook = ttk.Notebook(notebook_frame)
inner_notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
tab1 = ttk.Frame(inner_notebook)
tab2 = ttk.Frame(inner_notebook)
inner_notebook.add(tab1, text="標籤1")
inner_notebook.add(tab2, text="標籤2")
ttk.Label(tab1, text="標籤1的內容").pack(pady=20)
ttk.Label(tab2, text="標籤2的內容").pack(pady=20)
def create_advanced_widgets_tab(self, notebook):
"""創建高級Widget標籤頁"""
frame = ttk.Frame(notebook, padding=15)
notebook.add(frame, text="高級Widget")
# Progressbar
progress_frame = ttk.LabelFrame(frame, text="Progressbar 進度條", padding=10)
progress_frame.pack(fill=tk.X, pady=5)
self.progress = ttk.Progressbar(progress_frame, orient=tk.HORIZONTAL,
length=200, mode='determinate')
self.progress.pack(pady=5)
self.progress['value'] = 50
ttk.Button(progress_frame, text="增加進度",
command=self.increase_progress).pack(side=tk.LEFT, padx=5)
ttk.Button(progress_frame, text="重置進度",
command=self.reset_progress).pack(side=tk.LEFT, padx=5)
# Treeview
tree_frame = ttk.LabelFrame(frame, text="Treeview 樹形視圖", padding=10)
tree_frame.pack(fill=tk.BOTH, expand=True, pady=5)
tree = ttk.Treeview(tree_frame, columns=("姓名", "年齡", "城市"), show="headings")
tree.heading("姓名", text="姓名")
tree.heading("年齡", text="年齡")
tree.heading("城市", text="城市")
# 添加示例數據
data = [
("張三", "25", "北京"),
("李四", "30", "上海"),
("王五", "28", "廣州"),
("趙六", "35", "深圳")
]
for item in data:
tree.insert("", tk.END, values=item)
tree.pack(fill=tk.BOTH, expand=True)
# Separator
separator_frame = ttk.LabelFrame(frame, text="Separator 分隔符", padding=10)
separator_frame.pack(fill=tk.X, pady=5)
ttk.Label(separator_frame, text="上方內容").pack(pady=5)
ttk.Separator(separator_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, padx=10, pady=5)
ttk.Label(separator_frame, text="下方內容").pack(pady=5)
# Sizegrip
sizegrip_frame = ttk.LabelFrame(frame, text="Sizegrip 大小調整柄", padding=10)
sizegrip_frame.pack(fill=tk.X, pady=5)
ttk.Sizegrip(sizegrip_frame).pack(side=tk.RIGHT)
ttk.Label(sizegrip_frame, text="拖動右下角調整窗口大小").pack(side=tk.LEFT)
def show_message(self, message):
"""顯示消息"""
messagebox.showinfo("消息", message)
def increase_progress(self):
"""增加進度"""
current = self.progress['value']
if current < 100:
self.progress['value'] = current + 10
def reset_progress(self):
"""重置進度"""
self.progress['value'] = 0
if __name__ == "__main__":
root = tk.Tk()
app = WidgetGallery(root)
root.mainloop()
實際應用示例
示例3:綜合應用程序
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext, filedialog
import json
import datetime
class TaskManagerApp:
def __init__(self, root):
self.root = root
self.tasks = []
self.setup_ui()
self.load_sample_tasks()
def setup_ui(self):
"""設置用户界面"""
self.root.title("任務管理器 - Tkinter Widget綜合應用")
self.root.geometry("1200x800")
# 創建主容器
main_container = ttk.Frame(self.root)
main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 創建標題
title_label = ttk.Label(main_container, text="個人任務管理器",
font=("Arial", 20, "bold"))
title_label.pack(pady=(0, 20))
# 創建主要內容區域
content_frame = ttk.Frame(main_container)
content_frame.pack(fill=tk.BOTH, expand=True)
# 左側任務列表
self.create_task_list_panel(content_frame)
# 右側任務詳情
self.create_task_detail_panel(content_frame)
# 底部狀態欄
self.create_status_bar(main_container)
def create_task_list_panel(self, parent):
"""創建任務列表面板"""
list_frame = ttk.LabelFrame(parent, text="任務列表", padding=10)
list_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
# 搜索和過濾
search_frame = ttk.Frame(list_frame)
search_frame.pack(fill=tk.X, pady=(0, 10))
ttk.Label(search_frame, text="搜索:").pack(side=tk.LEFT)
self.search_var = tk.StringVar()
search_entry = ttk.Entry(search_frame, textvariable=self.search_var)
search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
search_entry.bind('<KeyRelease>', self.filter_tasks)
# 過濾選項
filter_frame = ttk.Frame(list_frame)
filter_frame.pack(fill=tk.X, pady=(0, 10))
ttk.Label(filter_frame, text="狀態過濾:").pack(side=tk.LEFT)
self.status_filter = ttk.Combobox(filter_frame, values=["全部", "待辦", "進行中", "完成"],
state="readonly")
self.status_filter.set("全部")
self.status_filter.pack(side=tk.LEFT, padx=5)
self.status_filter.bind('<<ComboboxSelected>>', self.filter_tasks)
# 任務列表
list_container = ttk.Frame(list_frame)
list_container.pack(fill=tk.BOTH, expand=True)
# 創建Treeview
columns = ("ID", "標題", "優先級", "狀態", "截止日期")
self.task_tree = ttk.Treeview(list_container, columns=columns, show="headings", height=15)
# 設置列
self.task_tree.heading("ID", text="ID")
self.task_tree.heading("標題", text="標題")
self.task_tree.heading("優先級", text="優先級")
self.task_tree.heading("狀態", text="狀態")
self.task_tree.heading("截止日期", text="截止日期")
self.task_tree.column("ID", width=50)
self.task_tree.column("標題", width=200)
self.task_tree.column("優先級", width=80)
self.task_tree.column("狀態", width=80)
self.task_tree.column("截止日期", width=100)
# 滾動條
scrollbar = ttk.Scrollbar(list_container, orient=tk.VERTICAL, command=self.task_tree.yview)
self.task_tree.configure(yscrollcommand=scrollbar.set)
self.task_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 綁定選擇事件
self.task_tree.bind('<<TreeviewSelect>>', self.on_task_select)
# 列表操作按鈕
list_buttons_frame = ttk.Frame(list_frame)
list_buttons_frame.pack(fill=tk.X, pady=(10, 0))
ttk.Button(list_buttons_frame, text="新建任務",
command=self.create_new_task).pack(side=tk.LEFT, padx=2)
ttk.Button(list_buttons_frame, text="刪除任務",
command=self.delete_task).pack(side=tk.LEFT, padx=2)
ttk.Button(list_buttons_frame, text="刷新列表",
command=self.refresh_task_list).pack(side=tk.LEFT, padx=2)
def create_task_detail_panel(self, parent):
"""創建任務詳情面板"""
detail_frame = ttk.LabelFrame(parent, text="任務詳情", padding=10)
detail_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(10, 0))
# 任務表單
form_frame = ttk.Frame(detail_frame)
form_frame.pack(fill=tk.X, pady=5)
# 標題
ttk.Label(form_frame, text="標題:").grid(row=0, column=0, sticky="w", pady=2)
self.title_var = tk.StringVar()
title_entry = ttk.Entry(form_frame, textvariable=self.title_var, width=40)
title_entry.grid(row=0, column=1, sticky="ew", pady=2, padx=5)
# 描述
ttk.Label(form_frame, text="描述:").grid(row=1, column=0, sticky="nw", pady=2)
self.description_text = scrolledtext.ScrolledText(form_frame, width=40, height=8)
self.description_text.grid(row=1, column=1, sticky="ew", pady=2, padx=5)
# 優先級
ttk.Label(form_frame, text="優先級:").grid(row=2, column=0, sticky="w", pady=2)
self.priority_var = tk.StringVar(value="中")
priority_combo = ttk.Combobox(form_frame, textvariable=self.priority_var,
values=["低", "中", "高"], state="readonly")
priority_combo.grid(row=2, column=1, sticky="w", pady=2, padx=5)
# 狀態
ttk.Label(form_frame, text="狀態:").grid(row=3, column=0, sticky="w", pady=2)
self.status_var = tk.StringVar(value="待辦")
status_combo = ttk.Combobox(form_frame, textvariable=self.status_var,
values=["待辦", "進行中", "完成"], state="readonly")
status_combo.grid(row=3, column=1, sticky="w", pady=2, padx=5)
# 截止日期
ttk.Label(form_frame, text="截止日期:").grid(row=4, column=0, sticky="w", pady=2)
date_frame = ttk.Frame(form_frame)
date_frame.grid(row=4, column=1, sticky="w", pady=2, padx=5)
self.due_date = ttk.Entry(date_frame, width=15)
self.due_date.pack(side=tk.LEFT)
ttk.Button(date_frame, text="今天",
command=self.set_today_date).pack(side=tk.LEFT, padx=5)
# 配置權重
form_frame.columnconfigure(1, weight=1)
# 詳情操作按鈕
detail_buttons_frame = ttk.Frame(detail_frame)
detail_buttons_frame.pack(fill=tk.X, pady=10)
ttk.Button(detail_buttons_frame, text="保存任務",
command=self.save_task, style='Accent.TButton').pack(side=tk.LEFT, padx=5)
ttk.Button(detail_buttons_frame, text="清除表單",
command=self.clear_form).pack(side=tk.LEFT, padx=5)
# 任務統計
stats_frame = ttk.LabelFrame(detail_frame, text="任務統計", padding=10)
stats_frame.pack(fill=tk.X, pady=10)
self.stats_label = ttk.Label(stats_frame, text="總任務: 0 | 完成: 0 | 進行中: 0 | 待辦: 0")
self.stats_label.pack()
def create_status_bar(self, parent):
"""創建狀態欄"""
status_frame = ttk.Frame(parent, relief="sunken", borderwidth=1)
status_frame.pack(fill=tk.X, pady=(10, 0))
self.status_var = tk.StringVar(value="就緒")
status_label = ttk.Label(status_frame, textvariable=self.status_var)
status_label.pack(side=tk.LEFT, padx=10)
# 當前時間
self.time_var = tk.StringVar()
time_label = ttk.Label(status_frame, textvariable=self.time_var)
time_label.pack(side=tk.RIGHT, padx=10)
self.update_time()
def load_sample_tasks(self):
"""加載示例任務"""
sample_tasks = [
{
"id": 1,
"title": "學習Tkinter",
"description": "深入學習Tkinter的各種組件和功能",
"priority": "高",
"status": "進行中",
"due_date": "2024-01-15"
},
{
"id": 2,
"title": "編寫項目文檔",
"description": "完成項目需求文檔和技術文檔",
"priority": "中",
"status": "待辦",
"due_date": "2024-01-20"
},
{
"id": 3,
"title": "代碼審查",
"description": "審查團隊成員的代碼提交",
"priority": "中",
"status": "完成",
"due_date": "2024-01-10"
}
]
self.tasks = sample_tasks
self.refresh_task_list()
def refresh_task_list(self):
"""刷新任務列表"""
# 清空現有數據
for item in self.task_tree.get_children():
self.task_tree.delete(item)
# 添加任務數據
for task in self.tasks:
self.task_tree.insert("", tk.END, values=(
task["id"],
task["title"],
task["priority"],
task["status"],
task["due_date"]
))
self.update_stats()
def filter_tasks(self, event=None):
"""過濾任務"""
search_text = self.search_var.get().lower()
status_filter = self.status_filter.get()
# 清空現有數據
for item in self.task_tree.get_children():
self.task_tree.delete(item)
# 過濾並添加任務
for task in self.tasks:
if search_text and search_text not in task["title"].lower():
continue
if status_filter != "全部" and status_filter != task["status"]:
continue
self.task_tree.insert("", tk.END, values=(
task["id"],
task["title"],
task["priority"],
task["status"],
task["due_date"]
))
def on_task_select(self, event):
"""任務選擇事件"""
selection = self.task_tree.selection()
if selection:
item = selection[0]
values = self.task_tree.item(item, "values")
task_id = int(values[0])
# 查找任務詳情
task = next((t for t in self.tasks if t["id"] == task_id), None)
if task:
self.load_task_to_form(task)
def load_task_to_form(self, task):
"""加載任務到表單"""
self.title_var.set(task["title"])
self.description_text.delete(1.0, tk.END)
self.description_text.insert(1.0, task["description"])
self.priority_var.set(task["priority"])
self.status_var.set(task["status"])
self.due_date.delete(0, tk.END)
self.due_date.insert(0, task["due_date"])
self.current_task_id = task["id"]
def create_new_task(self):
"""創建新任務"""
self.clear_form()
self.current_task_id = None
self.status_var.set("新建任務")
def save_task(self):
"""保存任務"""
if not self.title_var.get().strip():
messagebox.showerror("錯誤", "請輸入任務標題")
return
task_data = {
"title": self.title_var.get(),
"description": self.description_text.get(1.0, tk.END).strip(),
"priority": self.priority_var.get(),
"status": self.status_var.get(),
"due_date": self.due_date.get()
}
if hasattr(self, 'current_task_id') and self.current_task_id:
# 更新現有任務
task = next((t for t in self.tasks if t["id"] == self.current_task_id), None)
if task:
task.update(task_data)
else:
# 創建新任務
new_id = max([t["id"] for t in self.tasks], default=0) + 1
task_data["id"] = new_id
self.tasks.append(task_data)
self.refresh_task_list()
messagebox.showinfo("成功", "任務已保存")
def delete_task(self):
"""刪除任務"""
selection = self.task_tree.selection()
if not selection:
messagebox.showwarning("警告", "請選擇要刪除的任務")
return
if messagebox.askyesno("確認", "確定要刪除選中的任務嗎?"):
item = selection[0]
values = self.task_tree.item(item, "values")
task_id = int(values[0])
self.tasks = [t for t in self.tasks if t["id"] != task_id]
self.refresh_task_list()
self.clear_form()
def clear_form(self):
"""清除表單"""
self.title_var.set("")
self.description_text.delete(1.0, tk.END)
self.priority_var.set("中")
self.status_var.set("待辦")
self.due_date.delete(0, tk.END)
if hasattr(self, 'current_task_id'):
del self.current_task_id
def set_today_date(self):
"""設置今天日期"""
today = datetime.datetime.now().strftime("%Y-%m-%d")
self.due_date.delete(0, tk.END)
self.due_date.insert(0, today)
def update_stats(self):
"""更新統計信息"""
total = len(self.tasks)
completed = len([t for t in self.tasks if t["status"] == "完成"])
in_progress = len([t for t in self.tasks if t["status"] == "進行中"])
pending = len([t for t in self.tasks if t["status"] == "待辦"])
self.stats_label.config(
text=f"總任務: {total} | 完成: {completed} | 進行中: {in_progress} | 待辦: {pending}"
)
def update_time(self):
"""更新時間顯示"""
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.time_var.set(current_time)
self.root.after(1000, self.update_time)
if __name__ == "__main__":
root = tk.Tk()
# 配置樣式
style = ttk.Style()
style.configure('Accent.TButton', foreground='white', background='#3498db')
app = TaskManagerApp(root)
root.mainloop()
Widget的主要方法和屬性
# 創建Widget
widget = tk.Widget(parent, **options)
# 幾何管理方法
widget.pack(**options) # pack佈局
widget.grid(**options) # grid佈局
widget.place(**options) # place佈局
# 配置方法
widget.config(**options) # 配置選項
widget.cget('option') # 獲取選項值
widget.keys() # 獲取所有選項
# 狀態方法
widget['state'] = 'normal' # 設置狀態
widget.state(['disabled']) # 設置狀態 (ttk)
# 事件綁定
widget.bind('<event>', handler) # 綁定事件
widget.unbind('<event>') # 解綁事件
# 信息獲取
widget.winfo_x() # 獲取x座標
widget.winfo_y() # 獲取y座標
widget.winfo_width() # 獲取寬度
widget.winfo_height() # 獲取高度
widget.winfo_children() # 獲取子組件
# 焦點管理
widget.focus_set() # 設置焦點
widget.focus_get() # 獲取焦點組件
常用Widget選項
# 通用選項
text="文本" # 顯示文本
background="color" # 背景色
foreground="color" # 前景色
font=("Arial", 12) # 字體
width=100 # 寬度
height=50 # 高度
state="normal" # 狀態
# 佈局選項
padx=10 # 水平間距
pady=10 # 垂直間距
relief="solid" # 邊框樣式
borderwidth=2 # 邊框寬度
# 特定Widget選項
# Button
command=callback # 點擊命令
# Entry
show="*" # 顯示字符
textvariable=var # 文本變量
# Text
wrap="word" # 換行方式
# Listbox
selectmode="multiple" # 選擇模式
使用場景總結
- 表單應用:數據輸入和驗證
- 數據展示:表格、樹形視圖顯示數據
- 文件管理:文件瀏覽和操作
- 設置界面:應用程序配置
- 儀表板:數據可視化和管理
- 文本編輯:代碼編輯器、文檔編輯
- 遊戲界面:遊戲控制和狀態顯示
Widget是Tkinter應用程序的基礎,通過合理組合和使用各種Widget,可以創建出功能豐富、用户友好的桌面應用程序。