Python--Tkinter--标准 GUI 工具包
Tkinter 自学指南与完整案例 (纯deepseek版-自用)
Tkinter 是 Python 的标准 GUI 工具包,用于创建桌面应用程序。下面是一个完整的学习指南和案例,包含从基础到高级的应用。
基础框架
import tkinter as tk
from tkinter import ttk, messageboxclass App(tk.Tk):def __init__(self):super().__init__()self.title("Tkinter 学习应用")self.geometry("800x600")self.create_widgets()def create_widgets(self):# 创建标签self.label = ttk.Label(self, text="欢迎使用 Tkinter!", font=("Arial", 16))self.label.pack(pady=20)# 创建按钮self.button = ttk.Button(self, text="点击我", command=self.on_button_click)self.button.pack(pady=10)# 创建输入框self.entry = ttk.Entry(self, width=30)self.entry.pack(pady=10)self.entry.insert(0, "在这里输入文本")# 创建文本框self.text = tk.Text(self, height=10, width=50)self.text.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)self.text.insert("1.0", "这是一个多行文本框...\n")# 创建下拉框self.combo = ttk.Combobox(self, values=["选项1", "选项2", "选项3"])self.combo.pack(pady=10)self.combo.current(0)# 创建复选框self.check_var = tk.BooleanVar()self.check = ttk.Checkbutton(self, text="启用功能", variable=self.check_var)self.check.pack(pady=10)# 创建单选按钮self.radio_var = tk.StringVar(value="A")self.radio1 = ttk.Radiobutton(self, text="选项 A", variable=self.radio_var, value="A")self.radio2 = ttk.Radiobutton(self, text="选项 B", variable=self.radio_var, value="B")self.radio1.pack()self.radio2.pack()def on_button_click(self):entry_text = self.entry.get()combo_value = self.combo.get()check_state = self.check_var.get()radio_value = self.radio_var.get()self.text.insert("end", f"\n按钮被点击!\n输入内容: {entry_text}")self.text.insert("end", f"\n下拉框: {combo_value}, 复选框: {check_state}, 单选按钮: {radio_value}")messagebox.showinfo("信息", f"你选择了: {combo_value}")if __name__ == "__main__":app = App()app.mainloop()
完整案例:待办事项应用
import tkinter as tk
from tkinter import ttk, messagebox
import json
import os
from datetime import datetimeclass TodoApp(tk.Tk):def __init__(self):super().__init__()self.title("待办事项管理器")self.geometry("800x600")self.tasks = []self.load_tasks()self.create_widgets()def load_tasks(self):"""从文件加载任务"""if os.path.exists("tasks.json"):try:with open("tasks.json", "r") as f:self.tasks = json.load(f)except:self.tasks = []def save_tasks(self):"""保存任务到文件"""with open("tasks.json", "w") as f:json.dump(self.tasks, f)def create_widgets(self):"""创建界面组件"""# 创建主框架main_frame = ttk.Frame(self)main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)# 输入区域input_frame = ttk.LabelFrame(main_frame, text="添加新任务")input_frame.pack(fill=tk.X, pady=(0, 10))ttk.Label(input_frame, text="任务内容:").grid(row=0, column=0, padx=5, pady=5, sticky="w")self.task_entry = ttk.Entry(input_frame, width=40)self.task_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")ttk.Label(input_frame, text="优先级:").grid(row=0, column=2, padx=5, pady=5, sticky="w")self.priority_var = tk.StringVar(value="中")priority_combo = ttk.Combobox(input_frame, textvariable=self.priority_var, values=["低", "中", "高"], state="readonly", width=8)priority_combo.grid(row=0, column=3, padx=5, pady=5)ttk.Label(input_frame, text="截止日期:").grid(row=0, column=4, padx=5, pady=5, sticky="w")self.due_date_entry = ttk.Entry(input_frame, width=12)self.due_date_entry.grid(row=0, column=5, padx=5, pady=5)self.due_date_entry.insert(0, datetime.now().strftime("%Y-%m-%d"))add_btn = ttk.Button(input_frame, text="添加任务", command=self.add_task)add_btn.grid(row=0, column=6, padx=5, pady=5)# 任务列表list_frame = ttk.LabelFrame(main_frame, text="任务列表")list_frame.pack(fill=tk.BOTH, expand=True, pady=10)columns = ("id", "task", "priority", "due_date", "completed")self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", selectmode="browse")# 设置列宽和标题self.tree.column("id", width=50, anchor="center")self.tree.column("task", width=300, anchor="w")self.tree.column("priority", width=80, anchor="center")self.tree.column("due_date", width=100, anchor="center")self.tree.column("completed", width=80, anchor="center")self.tree.heading("id", text="ID")self.tree.heading("task", text="任务内容")self.tree.heading("priority", text="优先级")self.tree.heading("due_date", text="截止日期")self.tree.heading("completed", text="完成状态")# 添加滚动条scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.tree.yview)self.tree.configure(yscrollcommand=scrollbar.set)self.tree.pack(side="left", fill=tk.BOTH, expand=True)scrollbar.pack(side="right", fill="y")# 操作按钮btn_frame = ttk.Frame(main_frame)btn_frame.pack(fill=tk.X, pady=10)complete_btn = ttk.Button(btn_frame, text="标记完成", command=self.mark_completed)complete_btn.pack(side="left", padx=5)edit_btn = ttk.Button(btn_frame, text="编辑任务", command=self.edit_task)edit_btn.pack(side="left", padx=5)delete_btn = ttk.Button(btn_frame, text="删除任务", command=self.delete_task)delete_btn.pack(side="left", padx=5)# 状态栏self.status_var = tk.StringVar(value="就绪")status_bar = ttk.Label(self, textvariable=self.status_var, relief="sunken", anchor="w")status_bar.pack(side="bottom", fill=tk.X)# 填充任务列表self.refresh_task_list()def refresh_task_list(self):"""刷新任务列表"""# 清空现有列表for item in self.tree.get_children():self.tree.delete(item)# 添加任务到列表for idx, task in enumerate(self.tasks, 1):completed = "是" if task.get("completed", False) else "否"priority = task.get("priority", "中")# 根据优先级设置标签tags = ()if priority == "高":tags = ("high",)elif priority == "低":tags = ("low",)self.tree.insert("", "end", values=(idx,task["task"],priority,task.get("due_date", ""),completed), tags=tags)# 配置标签样式self.tree.tag_configure("high", background="#ffcccc") # 高优先级红色背景self.tree.tag_configure("low", background="#ccffcc") # 低优先级绿色背景def add_task(self):"""添加新任务"""task_text = self.task_entry.get().strip()if not task_text:messagebox.showerror("错误", "任务内容不能为空")returndue_date = self.due_date_entry.get().strip()priority = self.priority_var.get()new_task = {"task": task_text,"due_date": due_date,"priority": priority,"completed": False,"created_at": datetime.now().strftime("%Y-%m-%d %H:%M")}self.tasks.append(new_task)self.save_tasks()self.refresh_task_list()self.task_entry.delete(0, "end")self.status_var.set(f"任务 '{task_text}' 已添加")def get_selected_task(self):"""获取选中的任务"""selected = self.tree.selection()if not selected:messagebox.showinfo("提示", "请先选择一个任务")return Noneitem = self.tree.item(selected[0])idx = item["values"][0] - 1 # 从1开始的索引转列表索引if 0 <= idx < len(self.tasks):return idx, self.tasks[idx]return Nonedef mark_completed(self):"""标记任务为完成"""task_info = self.get_selected_task()if task_info is None:returnidx, task = task_infotask["completed"] = not task["completed"]self.save_tasks()self.refresh_task_list()status = "完成" if task["completed"] else "未完成"self.status_var.set(f"任务 '{task['task']}' 标记为 {status}")def edit_task(self):"""编辑任务"""task_info = self.get_selected_task()if task_info is None:returnidx, task = task_info# 创建编辑窗口edit_win = tk.Toplevel(self)edit_win.title("编辑任务")edit_win.geometry("400x300")edit_win.transient(self)edit_win.grab_set()ttk.Label(edit_win, text="任务内容:").pack(pady=(10, 5), padx=10, anchor="w")task_entry = ttk.Entry(edit_win, width=40)task_entry.pack(fill=tk.X, padx=10, pady=5)task_entry.insert(0, task["task"])ttk.Label(edit_win, text="优先级:").pack(pady=5, padx=10, anchor="w")priority_var = tk.StringVar(value=task.get("priority", "中"))priority_combo = ttk.Combobox(edit_win, textvariable=priority_var, values=["低", "中", "高"], state="readonly", width=8)priority_combo.pack(anchor="w", padx=10, pady=5)ttk.Label(edit_win, text="截止日期:").pack(pady=5, padx=10, anchor="w")due_date_entry = ttk.Entry(edit_win, width=12)due_date_entry.pack(anchor="w", padx=10, pady=5)due_date_entry.insert(0, task.get("due_date", ""))completed_var = tk.BooleanVar(value=task.get("completed", False))completed_check = ttk.Checkbutton(edit_win, text="已完成", variable=completed_var)completed_check.pack(anchor="w", padx=10, pady=10)def save_changes():task["task"] = task_entry.get().strip()task["priority"] = priority_var.get()task["due_date"] = due_date_entry.get().strip()task["completed"] = completed_var.get()self.save_tasks()self.refresh_task_list()edit_win.destroy()self.status_var.set(f"任务 '{task['task']}' 已更新")save_btn = ttk.Button(edit_win, text="保存", command=save_changes)save_btn.pack(pady=10)def delete_task(self):"""删除任务"""task_info = self.get_selected_task()if task_info is None:returnidx, task = task_infoif messagebox.askyesno("确认", f"确定要删除任务 '{task['task']}' 吗?"):del self.tasks[idx]self.save_tasks()self.refresh_task_list()self.status_var.set(f"任务 '{task['task']}' 已删除")if __name__ == "__main__":app = TodoApp()app.mainloop()
Tkinter 学习要点
1. 核心组件
组件 | 类名 | 描述 |
---|---|---|
窗口 | tk.Tk | 主应用程序窗口 |
标签 | ttk.Label | 显示文本或图像 |
按钮 | ttk.Button | 可点击按钮 |
输入框 | ttk.Entry | 单行文本输入 |
文本框 | tk.Text | 多行文本输入/显示 |
下拉框 | ttk.Combobox | 下拉选择框 |
复选框 | ttk.Checkbutton | 多选项选择 |
单选按钮 | ttk.Radiobutton | 单选项选择 |
列表框 | tk.Listbox | 项目列表显示 |
树状视图 | ttk.Treeview | 表格或树形数据展示 |
滚动条 | ttk.Scrollbar | 滚动支持 |
2. 布局管理
布局管理器 | 描述 | 示例 |
---|---|---|
pack() | 简单自动布局 | widget.pack(side="left", fill="y") |
grid() | 网格布局 | widget.grid(row=0, column=0, sticky="nsew") |
place() | 精确位置布局 | widget.place(x=10, y=20, width=100, height=50) |
3. 事件处理
# 按钮点击事件
button = ttk.Button(root, text="Click", command=on_click)# 键盘事件
entry = ttk.Entry(root)
entry.bind("<Return>", on_enter_pressed)# 鼠标事件
canvas = tk.Canvas(root)
canvas.bind("<Button-1>", on_left_click)
canvas.bind("<Motion>", on_mouse_move)# 窗口事件
root.protocol("WM_DELETE_WINDOW", on_window_close)
4. 对话框
from tkinter import messagebox, filedialog# 消息对话框
messagebox.showinfo("标题", "信息内容")
messagebox.showwarning("警告", "警告内容")
messagebox.showerror("错误", "错误内容")
answer = messagebox.askyesno("确认", "确定吗?")# 文件对话框
file_path = filedialog.askopenfilename(title="选择文件")
dir_path = filedialog.askdirectory(title="选择文件夹")
save_path = filedialog.asksaveasfilename(title="保存文件")
5. 样式与主题
# 创建样式对象
style = ttk.Style()# 查看可用主题
print(style.theme_names())# 设置主题
style.theme_use("clam")# 自定义样式
style.configure("TButton", padding=6, font=("Arial", 10))
style.map("TButton", foreground=[("pressed", "red"), ("active", "blue")],background=[("pressed", "!disabled", "black"), ("active", "white")])
学习资源
-
官方文档:
- Tkinter 文档
- Ttk 文档
-
教程推荐:
- Real Python: Python GUI With Tkinter
- TkDocs 教程
-
扩展库:
customtkinter
:现代化主题的 Tkintertkcalendar
:日期选择组件PIL
(Pillow):图像处理支持
-
项目实践:
- 计算器应用
- 文本编辑器
- 数据可视化工具
- 简单的游戏(如贪吃蛇)
总结
Tkinter 是 Python GUI 开发的入门首选:
- 优点:内置标准库、跨平台、简单易学
- 缺点:界面较传统、高级功能有限
- 适用场景:小型工具、教学示例、快速原型开发
通过本文提供的待办事项应用案例,您可以掌握:
- 创建主窗口和组件
- 使用多种布局管理器
- 处理用户交互事件
- 实现数据持久化(JSON)
- 创建对话框和子窗口
- 使用 Treeview 展示表格数据
- 应用样式和主题
继续学习时,建议:
- 从简单组件开始,逐步组合复杂界面
- 多参考官方文档和示例代码
- 尝试重写本文案例,添加新功能
- 探索更多 Tkinter 组件和扩展库