Python 进阶教程:Tkinter GUI 图形界面编程

📖 Tkinter 是 Python 标准库中自带的图形用户界面(GUI)开发工具,无需额外安装,是 Python 桌面应用开发的首选入门框架。


1. Tkinter简介

1.1 什么是Tkinter

Tkinter 是 Python 内置的 GUI(图形用户界面)编程框架,它是 Tcl/Tk 工具包的 Python 绑定。

1.2 Tkinter的优势

特性说明
✅ 无需安装Python 3.x 内置,随装随用
✅ 跨平台Windows、macOS、Linux 全支持
✅ 学习曲线平缓API 简洁直观,半小时入门
✅ 功能完整满足大多数桌面应用需求
✅ 轻量级内存占用小,启动快速

1.3 Tkinter能做什么

应用场景说明
📝 桌面工具记事本、计算器、文件管理器等
📊 数据可视化图表展示、数据报表工具
🎮 小游戏扫雷、贪吃蛇、五子棋等
📁 文件管理器文件浏览、批量重命名工具
📋 表单应用登录界面、注册页面、信息录入
🔧 系统配置设置面板、参数配置工具
📅 计划任务待办事项、日程管理、提醒工具
💬 聊天界面简易聊天室、消息通知窗口

2. 环境准备

2.1 检查Tkinter是否可用

import tkinter as tk

# 检查Tkinter版本
print(f"Tkinter版本: {tk.TkVersion}")

# 检查ttk主题支持
try:
    from tkinter import ttk
    print("ttk主题组件: 已安装")
except ImportError:
    print("ttk主题组件: 未安装")

2.2 安装Pillow(用于图片处理)

# 安装Pillow用于处理图片
pip install pillow

2.3 环境验证代码

import tkinter as tk
from tkinter import messagebox

def test_environment():
    """测试Tkinter环境是否正常"""
    try:
        root = tk.Tk()
        root.withdraw()  # 隐藏测试窗口
        
        messagebox.showinfo(
            "环境测试", 
            "🎉 Tkinter环境配置成功!\n\n可以开始GUI编程了。"
        )
        root.destroy()
        return True
    except Exception as e:
        messagebox.showerror("错误", f"环境配置失败:\n{e}")
        return False

if __name__ == "__main__":
    test_environment()

3. 第一个GUI程序

3.1 最简单的窗口

import tkinter as tk

# 创建主窗口
window = tk.Tk()

# 设置窗口标题
window.title("我的第一个GUI程序")

# 设置窗口大小
window.geometry("400x300")

# 运行主循环(显示窗口)
window.mainloop()

运行效果:

运行后会弹出一个空白窗口,标题为”我的第一个GUI程序”,大小为400×300像素。

3.2 带组件的窗口

import tkinter as tk

# 创建主窗口
window = tk.Tk()
window.title("Hello Tkinter")
window.geometry("300x200")

# 创建标签组件
label = tk.Label(
    window, 
    text="Hello, Tkinter! 🖥️",
    font=("Arial", 20),
    fg="blue"
)
label.pack(pady=50)  # pack() 将组件添加到窗口,pady设置上下间距

# 创建按钮
def on_click():
    label.config(text="按钮被点击了!🎉")

button = tk.Button(
    window, 
    text="点我",
    command=on_click,
    bg="#4CAF50",
    fg="white",
    width=10
)
button.pack()

# 运行主循环
window.mainloop()

运行效果:

图片[1]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

实际运行效果如上图所示,包含一个标题为”Hello Tkinter”的窗口,显示蓝色标题文本和绿色按钮。

3.3 程序结构解析

import tkinter as tk                    # 1️⃣ 导入tkinter模块

def create_window():
    # 2️⃣ 创建主窗口
    window = tk.Tk()
    
    # 3️⃣ 配置窗口
    window.title("窗口标题")
    window.geometry("800x600")
    
    # 4️⃣ 创建组件
    label = tk.Label(window, text="Hello")
    button = tk.Button(window, text="Click")
    
    # 5️⃣ 使用布局管理器放置组件
    label.pack()
    button.pack()
    
    # 6️⃣ 进入主循环
    window.mainloop()

if __name__ == "__main__":
    create_window()

4. 窗口基础配置

4.1 常用窗口属性

属性/方法说明示例
title()设置窗口标题window.title("标题")
geometry()设置窗口大小和位置window.geometry("800x600")
resizable()设置是否可调整大小window.resizable(False, False)
maxsize()设置最大尺寸window.maxsize(1024, 768)
minsize()设置最小尺寸window.minsize(400, 300)
configure(bg=)设置背景颜色window.configure(bg="white")
iconify()最小化窗口window.iconify()
state('zoomed')全屏/最大化window.state('zoomed')
withdraw()隐藏窗口window.withdraw()
deiconify()显示窗口window.deiconify()

4.2 窗口配置示例

import tkinter as tk

window = tk.Tk()

# 设置窗口标题
window.title("高级窗口配置")

# 设置窗口大小和位置: "宽x高+x偏移+y偏移"
window.geometry("800x600+100+100")

# 设置窗口是否可调整大小 (宽可调, 高可调)
window.resizable(True, True)

# 设置最大最小尺寸
window.minsize(400, 300)
window.maxsize(1920, 1080)

# 设置窗口透明度 (0.0-1.0)
window.attributes('-alpha', 0.95)

# 设置窗口图标
try:
    window.iconbitmap('app.ico')
except:
    pass  # 图标文件不存在时跳过

# 设置窗口背景色
window.configure(bg='#f0f0f0')

window.mainloop()

运行效果:

运行后会弹出一个配置完整的窗口,包含标题、大小限制、透明度等设置。

4.3 居中显示窗口

import tkinter as tk

def center_window(window, width, height):
    """将窗口居中显示"""
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()
    
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2
    
    window.geometry(f"{width}x{height}+{x}+{y}")

# 使用示例
window = tk.Tk()
window.title("居中窗口")

# 创建400x300的居中窗口
center_window(window, 400, 300)

window.mainloop()

5. 常用组件

5.1 组件一览表

组件英文名称功能说明
标签Label显示静态文本或图片
按钮Button创建可点击按钮
单行输入Entry用户输入单行文本
多行文本Text输入或显示多行文本
框架容器Frame组织和分组其他组件
复选框Checkbutton多选选项
单选框Radiobutton互斥选择
列表框Listbox显示项目列表
画布Canvas绘制图形、线条和图片
滑块Scale范围值选择
下拉框Combobox下拉选择列表
微调框Spinbox数值微调选择

5.2 Label(标签)

用于显示文本或图片。

import tkinter as tk
​
window = tk.Tk()
window.title("Label组件演示")
window.geometry("400x300")
​
# 基础文本标签
lbl_basic = tk.Label(
    window, 
    text="这是一个普通标签",
    font=("微软雅黑", 12)
)
lbl_basic.pack(pady=10)
​
# 彩色标签
lbl_color = tk.Label(
    window, 
    text="彩色文本标签",
    font=("Arial", 14, "bold"),
    fg="white",
    bg="#2196F3",      # 蓝色背景
    padx=20,
    pady=10
)
lbl_color.pack(pady=10)
​
# 带图片的标签
try:
    photo = tk.PhotoImage(file="python_logo.png")
    lbl_image = tk.Label(window, image=photo)
    lbl_image.pack(pady=10)
except:
    lbl_image = tk.Label(window, text="[Python Logo]")
    lbl_image.pack(pady=10)
​
# 多行文本标签
lbl_multiline = tk.Label(
    window, 
    text="第一行\n第二行\n第三行",
    justify="left",    # 左对齐
    relief=tk.RAISED,  # 边框样式
    borderwidth=2
)
lbl_multiline.pack(pady=10)
​
window.mainloop()

运行效果:

图片[2]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了四种不同的Label样式:普通文本标签、蓝色背景彩色标签、带边框标签和SUNKEN凹入效果标签。

5.3 Button(按钮)

用于响应用户点击事件。

import tkinter as tk
from tkinter import messagebox

def on_click():
    messagebox.showinfo("提示", "按钮被点击了!")

def on_hover(e):
    btn2.config(text="鼠标悬停中...")

def on_leave(e):
    btn2.config(text="悬停按钮")

window = tk.Tk()
window.title("Button组件演示")
window.geometry("400x300")

# 普通按钮
btn1 = tk.Button(
    window, 
    text="普通按钮",
    command=on_click,
    width=15,
    height=2
)
btn1.pack(pady=10)

# 带样式的按钮
btn2 = tk.Button(
    window, 
    text="悬停按钮",
    font=("微软雅黑", 12),
    bg="#4CAF50",
    fg="white",
    activebackground="#45a049",
    activeforeground="white",
    relief=tk.RAISED,
    bd=3
)
btn2.pack(pady=10)
btn2.bind("<Enter>", on_hover)
btn2.bind("<Leave>", on_leave)

# 禁用状态的按钮
btn3 = tk.Button(
    window, 
    text="禁用按钮",
    state=tk.DISABLED,
    width=15
)
btn3.pack(pady=10)

# 带图标的按钮
try:
    photo = tk.PhotoImage(file="icon.png")
    btn4 = tk.Button(window, image=photo, width=50, height=30)
    btn4.pack(pady=10)
except:
    btn4 = tk.Button(window, text="[图标按钮]", width=15)
    btn4.pack(pady=10)

window.mainloop()

运行效果:

图片[3]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了四种Button状态:普通按钮、绿色样式按钮、红色样式按钮和禁用状态按钮(灰色不可点击)。

5.4 Entry(单行输入框)

用于用户输入单行文本。

import tkinter as tk
from tkinter import messagebox

def get_input():
    text = entry.get()
    messagebox.showinfo("输入内容", f"你输入了: {text}")

def clear_input():
    entry.delete(0, tk.END)

def show_password():
    if show_var.get():
        entry.config(show="")
    else:
        entry.config(show="*")

window = tk.Tk()
window.title("Entry组件演示")
window.geometry("400x250")

# 标签
tk.Label(window, text="用户名:", font=("Arial", 12)).pack(pady=5)

# 普通输入框
entry = tk.Entry(window, width=30, font=("Arial", 12))
entry.insert(0, "请输入用户名")
entry.pack(pady=5)

# 密码输入框
tk.Label(window, text="密码:", font=("Arial", 12)).pack(pady=5)

# 密码显示切换
show_var = tk.BooleanVar()
chk_show = tk.Checkbutton(
    window, 
    text="显示密码", 
    variable=show_var,
    command=show_password
)
chk_show.pack()

# 创建密码输入框
entry_password = tk.Entry(window, width=30, font=("Arial", 12), show="*")
entry_password.pack(pady=5)

# 按钮组
btn_frame = tk.Frame(window)
btn_frame.pack(pady=15)

tk.Button(btn_frame, text="获取输入", command=get_input).pack(side=tk.LEFT, padx=5)
tk.Button(btn_frame, text="清空", command=clear_input).pack(side=tk.LEFT, padx=5)

window.mainloop()

运行效果:

图片[4]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Entry输入框组件,包括用户名输入框(明文显示)和密码输入框(密文显示),以及登录按钮。

5.5 Text(多行文本框)

用于输入或显示多行文本。

import tkinter as tk
from tkinter import scrolledtext

def save_content():
    content = text_area.get("1.0", tk.END)
    with open("notes.txt", "w", encoding="utf-8") as f:
        f.write(content)
    status.config(text="✅ 保存成功!")

def clear_content():
    text_area.delete("1.0", tk.END)
    status.config(text="已清空")

window = tk.Tk()
window.title("Text组件演示")
window.geometry("450x350")

# 创建带滚动条的文本区域
text_area = scrolledtext.ScrolledText(
    window, 
    width=50, 
    height=15,
    font=("Consolas", 11),
    wrap=tk.WORD,
    undo=True  # 支持撤销
)
text_area.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)

# 添加一些初始文本
text_area.insert("1.0", "# 我的笔记\n\n这是一个多行文本编辑器...\n")

# 按钮栏
btn_frame = tk.Frame(window)
btn_frame.pack(pady=5)

tk.Button(btn_frame, text="保存", command=save_content, width=10).pack(side=tk.LEFT, padx=5)
tk.Button(btn_frame, text="清空", command=clear_content, width=10).pack(side=tk.LEFT, padx=5)

# 状态栏
status = tk.Label(window, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
status.pack(fill=tk.X, padx=5, pady=5)

window.mainloop()

运行效果:

图片[5]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了ScrolledText多行文本编辑器组件,带有滚动条,支持保存和清空功能。

5.6 Frame(框架容器)

用于组织和分组其他组件。

import tkinter as tk

window = tk.Tk()
window.title("Frame组件演示")
window.geometry("500x300")

# 创建主Frame(白色背景)
main_frame = tk.Frame(window, bg="#ffffff", relief=tk.RAISED, bd=2)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

# 标题
tk.Label(
    main_frame, 
    text="用户注册表单", 
    font=("微软雅黑", 16, "bold"),
    bg="#ffffff"
).pack(pady=10)

# 创建左侧Frame(用户名区域)
left_frame = tk.Frame(main_frame, bg="#f5f5f5", relief=tk.SUNKEN, bd=1)
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)

tk.Label(left_frame, text="用户名", bg="#f5f5f5").pack(pady=5)
tk.Entry(left_frame, width=20).pack(pady=5)

tk.Label(left_frame, text="邮箱", bg="#f5f5f5").pack(pady=5)
tk.Entry(left_frame, width=20).pack(pady=5)

# 创建右侧Frame(密码区域)
right_frame = tk.Frame(main_frame, bg="#f5f5f5", relief=tk.SUNKEN, bd=1)
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)

tk.Label(right_frame, text="密码", bg="#f5f5f5").pack(pady=5)
tk.Entry(right_frame, width=20, show="*").pack(pady=5)

tk.Label(right_frame, text="确认密码", bg="#f5f5f5").pack(pady=5)
tk.Entry(right_frame, width=20, show="*").pack(pady=5)

# 底部按钮
tk.Button(main_frame, text="注册", width=10, bg="#4CAF50", fg="white").pack(pady=15)

window.mainloop()

运行效果:

图片[6]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Frame框架容器的使用,左侧蓝色区域为”基本信息”,右侧绿色区域为”安全信息”,中间有注册按钮。

5.7 Checkbutton(复选框)和 Radiobutton(单选框)

import tkinter as tk
from tkinter import messagebox

def show_selection():
    # 获取复选框状态
    checks = []
    if var_accept.get():
        checks.append("✅ 接受协议")
    
    # 获取单选框状态
    gender = gender_var.get()
    
    result = f"复选框: {', '.join(checks) if checks else '未接受'}\n"
    result += f"性别: {gender}"
    messagebox.showinfo("选择结果", result)

window = tk.Tk()
window.title("复选框和单选框演示")
window.geometry("350x300")

# 复选框区域
check_frame = tk.LabelFrame(window, text="兴趣爱好", padx=10, pady=10)
check_frame.pack(pady=10, padx=10, fill=tk.X)

var_hobby1 = tk.BooleanVar()
var_hobby2 = tk.BooleanVar()
var_hobby3 = tk.BooleanVar()

tk.Checkbutton(check_frame, text="编程 💻", variable=var_hobby1).pack(anchor=tk.W)
tk.Checkbutton(check_frame, text="阅读 📚", variable=var_hobby2).pack(anchor=tk.W)
tk.Checkbutton(check_frame, text="音乐 🎵", variable=var_hobby3).pack(anchor=tk.W)

# 单选框区域
radio_frame = tk.LabelFrame(window, text="性别", padx=10, pady=10)
radio_frame.pack(pady=10, padx=10, fill=tk.X)

gender_var = tk.StringVar(value="未知")

tk.Radiobutton(radio_frame, text="男 🧑", variable=gender_var, value="男").pack(anchor=tk.W)
tk.Radiobutton(radio_frame, text="女 👩", variable=gender_var, value="女").pack(anchor=tk.W)
tk.Radiobutton(radio_frame, text="保密 🙈", variable=gender_var, value="保密").pack(anchor=tk.W)

# 协议复选框
var_accept = tk.BooleanVar()
tk.Checkbutton(window, text="我已阅读并同意用户协议", variable=var_accept).pack(pady=10)

# 提交按钮
tk.Button(window, text="提交", command=show_selection, width=15).pack(pady=10)

window.mainloop()

运行效果:

图片[7]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了复选框(Checkbutton,可多选)和单选框(Radiobutton,互斥选择)的使用效果。

5.8 Listbox(列表框)

import tkinter as tk
from tkinter import Listbox, END, ANCHOR

def add_item():
    item = entry.get()
    if item:
        listbox.insert(END, item)
        entry.delete(0, END)

def delete_item():
    try:
        index = listbox.curselection()[0]
        listbox.delete(index)
    except:
        pass

def show_selected(event):
    try:
        index = listbox.curselection()[0]
        selected = listbox.get(index)
        lbl_selected.config(text=f"已选择: {selected}")
    except:
        pass

window = tk.Tk()
window.title("Listbox组件演示")
window.geometry("300x350")

# 输入区域
frame_top = tk.Frame(window)
frame_top.pack(pady=10)

entry = tk.Entry(frame_top, width=20)
entry.pack(side=tk.LEFT, padx=5)

tk.Button(frame_top, text="添加", command=add_item, width=6).pack(side=tk.LEFT)

# 列表框
listbox = Listbox(window, width=35, height=12, font=("Arial", 11))
listbox.pack(pady=10)

# 预填充一些项目
fruits = ["苹果 🍎", "香蕉 🍌", "橙子 🍊", "葡萄 🍇", "草莓 🍓"]
for fruit in fruits:
    listbox.insert(END, fruit)

listbox.bind("<<ListboxSelect>>", show_selected)

# 操作按钮
btn_frame = tk.Frame(window)
btn_frame.pack(pady=5)

tk.Button(btn_frame, text="删除", command=delete_item, width=8).pack(side=tk.LEFT, padx=5)

# 显示选择结果
lbl_selected = tk.Label(window, text="已选择: ", font=("Arial", 10))
lbl_selected.pack(pady=5)

window.mainloop()

运行效果:

图片[8]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Listbox列表框组件,显示水果列表,支持选择和删除操作。

5.9 Canvas(画布)

用于绘制图形、线条和图片。

import tkinter as tk

window = tk.Tk()
window.title("Canvas组件演示")
window.geometry("400x350")

canvas = tk.Canvas(window, width=380, height=280, bg="white", relief=tk.SUNKEN, bd=2)
canvas.pack(pady=10)

# 绘制矩形
canvas.create_rectangle(20, 20, 120, 80, fill="#FF6B6B", outline="#D63031", width=2)

# 绘制椭圆
canvas.create_oval(150, 20, 250, 80, fill="#74B9FF", outline="#0984E3", width=2)

# 绘制多边形(三角形)
canvas.create_polygon(270, 80, 320, 80, 295, 30, fill="#55EFC4", outline="#00B894")

# 绘制文字
canvas.create_text(70, 50, text="矩形", font=("Arial", 12, "bold"), fill="white")
canvas.create_text(200, 50, text="椭圆", font=("Arial", 12, "bold"), fill="white")

# 绘制线条
canvas.create_line(20, 120, 120, 200, fill="#A29BFE", width=3)
canvas.create_line(120, 120, 20, 200, fill="#A29BFE", width=3)

# 绘制弧形
canvas.create_arc(150, 120, 250, 220, start=0, extent=180, fill="#FDCB6E")

# 绘制笑脸
canvas.create_oval(320, 130, 370, 180, fill="#FFEAA7", outline="black", width=1)
canvas.create_oval(330, 145, 340, 155, fill="black")  # 左眼
canvas.create_oval(350, 145, 360, 155, fill="black")  # 右眼
canvas.create_arc(330, 155, 360, 175, start=0, extent=-180, fill="black")  # 微笑

# 绘制网格线
for i in range(30, 380, 30):
    canvas.create_line(i, 220, i, 270, fill="#ddd")
for i in range(220, 280, 25):
    canvas.create_line(30, i, 380, i, fill="#ddd")

# 绘制进度条背景
canvas.create_rectangle(30, 230, 380, 250, fill="#eee", outline="#ddd")
canvas.create_rectangle(30, 230, 200, 250, fill="#00B894", outline="")

# 添加标注
canvas.create_text(200, 265, text="进度: 60%", font=("Arial", 10), anchor=tk.CENTER)

window.mainloop()

运行效果:

图片[9]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Canvas画布组件的绘图能力,包括矩形、椭圆、三角形、线条、弧形、笑脸和进度条。

5.10 Scale(滑块)和 Spinbox(微调框)

import tkinter as tk
from tkinter import ttk

def on_scale_change(value):
    lbl_scale.config(text=f"滑块值: {int(float(value))}")

def on_spin_change():
    lbl_spin.config(text=f"微调值: {spin_var.get()}")

window = tk.Tk()
window.title("Scale和Spinbox演示")
window.geometry("350x300")

# Scale(滑块)演示
scale_frame = tk.LabelFrame(window, text="滑块组件", padx=10, pady=10)
scale_frame.pack(pady=10, padx=10, fill=tk.X)

lbl_scale = tk.Label(scale_frame, text="滑块值: 50", font=("Arial", 12))
lbl_scale.pack()

scale = ttk.Scale(
    scale_frame, 
    from_=0, 
    to=100, 
    orient=tk.HORIZONTAL,
    command=on_scale_change
)
scale.set(50)  # 设置默认值
scale.pack(fill=tk.X, pady=5)

# Spinbox(微调框)演示
spin_frame = tk.LabelFrame(window, text="微调框组件", padx=10, pady=10)
spin_frame.pack(pady=10, padx=10, fill=tk.X)

lbl_spin = tk.Label(spin_frame, text="微调值: 0", font=("Arial", 12))
lbl_spin.pack()

spin_var = tk.IntVar(value=0)
spinbox = ttk.Spinbox(
    spin_frame, 
    from_=-50, 
    to=50,
    textvariable=spin_var,
    command=on_spin_change,
    width=15
)
spinbox.pack(pady=5)

# 数值选择Spinbox
tk.Label(spin_frame, text="选择数量:").pack(pady=5)
spin2 = ttk.Spinbox(spin_frame, from_=1, to=100, width=15)
spin2.pack()

window.mainloop()

运行效果:

图片[10]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Scale滑块组件(用于音量调节等连续值选择)和Spinbox微调框组件(用于数值选择)。


6. 布局管理器

6.1 三大布局管理器对比

布局管理器说明适用场景
pack()按顺序堆叠组件简单垂直/水平排列
grid()网格行列布局表格、表单等对齐布局
place()精确坐标定位需要精确控制位置的场景

6.2 pack() 布局

import tkinter as tk

window = tk.Tk()
window.title("pack()布局演示")
window.geometry("400x400")

# pack的side参数
top_frame = tk.Frame(window, bg="#FF6B6B", width=400, height=80)
top_frame.pack(side=tk.TOP, fill=tk.X)

tk.Label(top_frame, text="顶部区域 - TOP", bg="#FF6B6B", fg="white", font=("Arial", 14)).pack(pady=20)

# 中间区域
middle_frame = tk.Frame(window, bg="#4ECDC4", width=400, height=80)
middle_frame.pack(side=tk.TOP, fill=tk.X, pady=5)

tk.Label(middle_frame, text="中间区域", bg="#4ECDC4", fg="white", font=("Arial", 14)).pack(pady=20)

# 底部区域使用expand
bottom_frame = tk.Frame(window, bg="#45B7D1")
bottom_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

# fill参数演示
btn_frame = tk.Frame(bottom_frame, bg="#96CEB4")
btn_frame.pack(pady=10, padx=20, fill=tk.X)

tk.Button(btn_frame, text="填充X").pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
tk.Button(btn_frame, text="填充X").pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
tk.Button(btn_frame, text="填充X").pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

window.mainloop()

运行效果:

pack()布局会按顺序堆叠组件,支持TOP/BOTTOM/LEFT/RIGHT四个方向,以及fill和expand参数控制填充行为。

6.3 grid() 布局

import tkinter as tk

window = tk.Tk()
window.title("grid()布局演示")
window.geometry("450x400")

# 创建表单布局
labels = ["姓名:", "邮箱:", "电话:", "地址:", "城市:", "邮编:"]
entries = ["张伟", "zhang@example.com", "13800138000", "北京市朝阳区", "北京", "100000"]

for i, (label_text, default_value) in enumerate(zip(labels, entries)):
    tk.Label(window, text=label_text, font=("Arial", 12)).grid(
        row=i, column=0, sticky=tk.E, padx=10, pady=8
    )
    
    entry = tk.Entry(window, width=30, font=("Arial", 12))
    entry.insert(0, default_value)
    entry.grid(row=i, column=1, padx=10, pady=8)

# 设置列权重,使Entry列可以扩展
window.columnconfigure(1, weight=1)

# 按钮区域
btn_frame = tk.Frame(window)
btn_frame.grid(row=7, column=0, columnspan=2, pady=20)

tk.Button(btn_frame, text="提交", width=10, bg="#4CAF50", fg="white").pack(side=tk.LEFT, padx=10)
tk.Button(btn_frame, text="取消", width=10).pack(side=tk.LEFT, padx=10)

window.mainloop()

运行效果:

grid()布局将窗口划分为行和列的网格,适合表单等需要对齐的布局场景。

6.4 place() 布局

import tkinter as tk

window = tk.Tk()
window.title("place()布局演示")
window.geometry("400x300")

# 使用place精确放置组件
canvas = tk.Canvas(window, width=380, height=200, bg="#f0f0f0", relief=tk.SUNKEN)
canvas.pack(pady=10)

# 绘制一个简单的登录界面布局
# 用户名标签
canvas.create_text(80, 40, text="用户名:", font=("Arial", 12), anchor=tk.E)
# 用户名输入框
canvas.create_rectangle(90, 25, 280, 55, fill="white", outline="gray")
canvas.create_text(100, 40, text="请输入用户名", fill="gray")

# 密码标签
canvas.create_text(80, 90, text="密码:", font=("Arial", 12), anchor=tk.E)
# 密码输入框
canvas.create_rectangle(90, 75, 280, 105, fill="white", outline="gray")
canvas.create_text(100, 90, text="••••••••", fill="gray")

# 登录按钮
canvas.create_rectangle(140, 130, 220, 165, fill="#4CAF50", outline="#388E3C")
canvas.create_text(180, 147, text="登录", font=("Arial", 12, "bold"), fill="white")

# 说明文本
canvas.create_text(190, 190, text="place() 使用 x,y 坐标精确定位", font=("Arial", 9), fill="#666")

window.mainloop()

运行效果:

place()布局使用精确的(x, y)坐标定位组件,适合需要精确控制位置的场景。


7. 事件处理

7.1 事件类型一览

事件类型说明示例
<Button-1>鼠标左键点击按钮点击
<Button-2>鼠标中键点击滚轮点击
<Button-3>鼠标右键点击右键菜单
<Double-Button-1>双击Listbox双击
<Enter>鼠标进入悬停效果
<Leave>鼠标离开悬停效果
<Key>键盘按键全局键盘事件
<KeyPress>按键按下同上
<FocusIn>获得焦点输入框焦点
<FocusOut>失去焦点输入验证
<Return>回车键表单提交
<Escape>ESC键取消操作

7.2 事件绑定示例

import tkinter as tk
from tkinter import messagebox

def on_key_press(event):
    lbl_key.config(text=f"按键: {event.char} (键码: {event.keycode})")

def on_click(event):
    x, y = event.x, event.y
    canvas.create_oval(x-5, y-5, x+5, y+5, fill="#FF6B6B")
    lbl_pos.config(text=f"点击位置: ({x}, {y})")

def on_right_click(event):
    canvas.delete("all")  # 清空画布
    lbl_pos.config(text="画布已清空")

window = tk.Tk()
window.title("事件处理演示")
window.geometry("450x350")

# 键盘事件区域
key_frame = tk.LabelFrame(window, text="键盘事件", padx=10, pady=5)
key_frame.pack(pady=5, padx=10, fill=tk.X)

lbl_key = tk.Label(key_frame, text="请按下任意键...", font=("Arial", 11))
lbl_key.pack()

# 画布演示鼠标事件
canvas = tk.Canvas(window, width=430, height=200, bg="white", relief=tk.SUNKEN)
canvas.pack(pady=5, padx=10)

# 鼠标点击事件
canvas.bind("<Button-1>", on_click)

# 右键清空
canvas.bind("<Button-3>", on_right_click)

# 右键菜单
def show_context_menu(event):
    menu.post(event.x_root, event.y_root)

menu = tk.Menu(window, tearoff=0)
menu.add_command(label="清空", command=lambda: canvas.delete("all"))
menu.add_command(label="撤销", command=lambda: canvas.delete(canvas.find_all()[-1]))
menu.add_separator()
menu.add_command(label="退出", command=window.quit)

canvas.bind("<Button-3>", show_context_menu)

# 位置显示
lbl_pos = tk.Label(window, text="点击位置: (-, -)", relief=tk.SUNKEN)
lbl_pos.pack(pady=5)

# 全局键盘监听
window.bind("<Key>", on_key_press)
window.focus_set()  # 获取焦点以便接收键盘事件

window.mainloop()

运行效果:

事件处理演示展示了键盘事件监听和鼠标点击事件,点击画布会在对应位置绘制圆点。

7.3 组件command参数

import tkinter as tk
from tkinter import messagebox

def on_click():
    messagebox.showinfo("提示", "按钮被点击!")

def on_focus_in(event):
    event.widget.config(bg="#E3F2FD")

def on_focus_out(event):
    event.widget.config(bg="white")

window = tk.Tk()
window.title("command参数演示")
window.geometry("350x250")

# Button的command参数
tk.Button(window, text="点击我", command=on_click, width=15).pack(pady=10)

# Entry的focus事件
tk.Label(window, text="输入框焦点事件:").pack(pady=5)
entry = tk.Entry(window, width=25, font=("Arial", 12))
entry.pack()
entry.bind("<FocusIn>", on_focus_in)
entry.bind("<FocusOut>", on_focus_out)

# 计数器示例
counter = [0]
def update_counter():
    counter[0] += 1
    lbl_counter.config(text=f"计数器: {counter[0]}")

tk.Button(window, text="计数+1", command=update_counter, width=15).pack(pady=10)
lbl_counter = tk.Label(window, text="计数器: 0", font=("Arial", 14))
lbl_counter.pack()

window.mainloop()

8. 高级组件

8.1 Combobox(下拉框)

import tkinter as tk
from tkinter import ttk

def on_select(event):
    selected = combo.get()
    lbl_result.config(text=f"选择: {selected}")

window = tk.Tk()
window.title("Combobox演示")
window.geometry("300x200")

tk.Label(window, text="选择一个编程语言:", font=("Arial", 12)).pack(pady=10)

# 创建Combobox
combo = ttk.Combobox(window, width=20, font=("Arial", 12))
combo['values'] = ("Python", "Java", "JavaScript", "C++", "Go", "Rust")
combo.current(0)  # 设置默认值
combo.pack(pady=10)

combo.bind("<<ComboboxSelected>>", on_select)

lbl_result = tk.Label(window, text="选择: Python", font=("Arial", 14))
lbl_result.pack(pady=20)

window.mainloop()

8.2 Treeview(树形视图)

import tkinter as tk
from tkinter import ttk

window = tk.Tk()
window.title("Treeview演示")
window.geometry("400x350")

# 创建Treeview
tree = ttk.Treeview(window, columns=("姓名", "年龄", "城市"), show="headings", height=10)
tree.pack(pady=10)

# 设置列
tree.heading("姓名", text="姓名")
tree.heading("年龄", text="年龄")
tree.heading("城市", text="城市")

tree.column("姓名", width=120, anchor=tk.CENTER)
tree.column("年龄", width=80, anchor=tk.CENTER)
tree.column("城市", width=120, anchor=tk.CENTER)

# 添加数据
data = [
    ("张伟", "28", "北京"),
    ("李娜", "25", "上海"),
    ("王强", "32", "深圳"),
    ("刘芳", "27", "广州"),
]

for person in data:
    tree.insert("", tk.END, values=person)

# 添加按钮
def add_row():
    tree.insert("", tk.END, values=("新增", "30", "新城市"))

def delete_row():
    selected = tree.selection()
    if selected:
        tree.delete(selected)

btn_frame = tk.Frame(window)
btn_frame.pack(pady=10)

tk.Button(btn_frame, text="添加", command=add_row, width=8).pack(side=tk.LEFT, padx=5)
tk.Button(btn_frame, text="删除", command=delete_row, width=8).pack(side=tk.LEFT, padx=5)

window.mainloop()

运行效果:

图片[11]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Treeview树形视图组件,以表格形式展示数据(姓名、年龄、城市),支持添加和删除操作。

8.3 Notebook(选项卡)

import tkinter as tk
from tkinter import ttk

window = tk.Tk()
window.title("Notebook选项卡演示")
window.geometry("400x300")

# 创建Notebook
notebook = ttk.Notebook(window)
notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

# 第一个选项卡
tab1 = tk.Frame(notebook, bg="#E8F5E9")
notebook.add(tab1, text="📊 数据")
tk.Label(tab1, text="数据分析内容", font=("Arial", 14), bg="#E8F5E9").pack(pady=30)

# 第二个选项卡
tab2 = tk.Frame(notebook, bg="#E3F2FD")
notebook.add(tab2, text="📈 图表")
tk.Label(tab2, text="图表展示内容", font=("Arial", 14), bg="#E3F2FD").pack(pady=30)

# 第三个选项卡
tab3 = tk.Frame(notebook, bg="#FFF3E0")
notebook.add(tab3, text="⚙️ 设置")
tk.Label(tab3, text="系统设置内容", font=("Arial", 14), bg="#FFF3E0").pack(pady=30)

window.mainloop()

运行效果:

图片[12]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了Notebook选项卡组件,包含”数据统计”、”图表展示”和”系统设置”三个选项卡。


9. 菜单与对话框

9.1 创建菜单栏

import tkinter as tk
from tkinter import messagebox, filedialog

def new_file():
    messagebox.showinfo("菜单", "新建文件")

def open_file():
    filename = filedialog.askopenfilename(
        title="选择文件",
        filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
    )
    if filename:
        messagebox.showinfo("打开", f"选择了: {filename}")

def save_file():
    messagebox.save_openfilename = filedialog.asksaveasfilename(
        title="保存文件",
        defaultextension=".txt",
        filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
    )

window = tk.Tk()
window.title("菜单栏演示")
window.geometry("400x300")

# 创建菜单栏
menubar = tk.Menu(window)
window.config(menu=menubar)

# 文件菜单
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="文件", menu=file_menu)
file_menu.add_command(label="新建", command=new_file, accelerator="Ctrl+N")
file_menu.add_command(label="打开", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="保存", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="退出", command=window.quit)

# 编辑菜单
edit_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="编辑", menu=edit_menu)
edit_menu.add_command(label="撤销")
edit_menu.add_command(label="重做")
edit_menu.add_separator()
edit_menu.add_command(label="剪切")
edit_menu.add_command(label="复制")
edit_menu.add_command(label="粘贴")

# 帮助菜单
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="帮助", menu=help_menu)
help_menu.add_command(label="关于", command=lambda: messagebox.showinfo("关于", "Tkinter教程 v1.0"))
help_menu.add_command(label="使用手册")

window.mainloop()

运行效果:

图片[13]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了菜单栏(Menu)组件,包含”文件”、”编辑”和”帮助”三个菜单项。

9.2 消息对话框

import tkinter as tk
from tkinter import messagebox

window = tk.Tk()
window.title("对话框演示")
window.geometry("350x250")

def show_info():
    messagebox.showinfo("信息", "这是一条信息提示!")

def show_warning():
    messagebox.showwarning("警告", "这是一个警告信息!")

def show_error():
    messagebox.showerror("错误", "发生了一个错误!")

def ask_yesno():
    result = messagebox.askyesno("确认", "确定要继续吗?")
    lbl_result.config(text=f"结果: {result}")

def ask_okcancel():
    result = messagebox.askokcancel("提示", "操作不可逆,确定吗?")
    lbl_result.config(text=f"结果: {result}")

tk.Button(window, text="信息框", command=show_info, width=15).pack(pady=5)
tk.Button(window, text="警告框", command=show_warning, width=15).pack(pady=5)
tk.Button(window, text="错误框", command=show_error, width=15).pack(pady=5)
tk.Button(window, text="是/否对话框", command=ask_yesno, width=15).pack(pady=5)
tk.Button(window, text="确定/取消对话框", command=ask_okcancel, width=15).pack(pady=5)

lbl_result = tk.Label(window, text="结果: -", font=("Arial", 11))
lbl_result.pack(pady=15)

window.mainloop()

运行效果:

图片[14]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了四种常用的消息对话框:信息框、警告框、错误框和确认对话框。

9.3 文件对话框

import tkinter as tk
from tkinter import filedialog, colorchooser

def open_file():
    filename = filedialog.askopenfilename(
        title="打开文件",
        initialdir="/",
        filetypes=[
            ("文本文件", "*.txt"),
            ("Python文件", "*.py"),
            ("所有文件", "*.*")
        ]
    )
    if filename:
        lbl_file.config(text=f"打开: {filename}")

def save_file():
    filename = filedialog.asksaveasfilename(
        title="保存文件",
        defaultextension=".txt",
        filetypes=[
            ("文本文件", "*.txt"),
            ("所有文件", "*.*")
        ]
    )
    if filename:
        lbl_file.config(text=f"保存: {filename}")

def choose_color():
    color = colorchooser.askcolor(title="选择颜色")
    if color[1]:
        lbl_file.config(text=f"颜色: {color[1]}", fg=color[1])

window = tk.Tk()
window.title("文件对话框演示")
window.geometry("400x200")

tk.Button(window, text="打开文件", command=open_file, width=20).pack(pady=10)
tk.Button(window, text="保存文件", command=save_file, width=20).pack(pady=10)
tk.Button(window, text="选择颜色", command=choose_color, width=20).pack(pady=10)

lbl_file = tk.Label(window, text="请选择操作", font=("Arial", 11))
lbl_file.pack(pady=20)

window.mainloop()

10. 面向对象编程

10.1 基于类的窗口

import tkinter as tk
from tkinter import messagebox

class MyWindow:
    def __init__(self, master):
        self.master = master
        self.master.title("OOP窗口示例")
        self.master.geometry("300x200")
        
        self.create_widgets()
    
    def create_widgets(self):
        self.label = tk.Label(
            self.master, 
            text="面向对象窗口", 
            font=("Arial", 16)
        )
        self.label.pack(pady=20)
        
        self.button = tk.Button(
            self.master, 
            text="点击我", 
            command=self.on_click
        )
        self.button.pack(pady=10)
        
        self.entry = tk.Entry(self.master, width=20)
        self.entry.pack(pady=10)
    
    def on_click(self):
        text = self.entry.get() or "世界"
        messagebox.showinfo("问候", f"你好, {text}!")

# 使用
root = tk.Tk()
app = MyWindow(root)
root.mainloop()

10.2 多页面应用

import tkinter as tk

class MultiPageApp:
    def __init__(self, master):
        self.master = master
        self.master.title("多页面应用")
        self.master.geometry("400x300")
        
        # 创建容器Frame
        self.container = tk.Frame(self.master)
        self.container.pack(fill=tk.BOTH, expand=True)
        
        # 创建各个页面
        self.page1 = self.create_page1()
        self.page2 = self.create_page2()
        self.page3 = self.create_page3()
        
        # 默认显示第一页
        self.show_page(self.page1)
        
        # 导航按钮
        self.create_nav()
    
    def create_page1(self):
        frame = tk.Frame(self.container, bg="#E3F2FD")
        tk.Label(frame, text="📊 数据统计页面", font=("Arial", 18), bg="#E3F2FD").pack(pady=50)
        tk.Label(frame, text="这是数据统计模块", bg="#E3F2FD").pack()
        return frame
    
    def create_page2(self):
        frame = tk.Frame(self.container, bg="#E8F5E9")
        tk.Label(frame, text="⚙️ 设置页面", font=("Arial", 18), bg="#E8F5E9").pack(pady=50)
        tk.Label(frame, text="这是系统设置模块", bg="#E8F5E9").pack()
        return frame
    
    def create_page3(self):
        frame = tk.Frame(self.container, bg="#FFF3E0")
        tk.Label(frame, text="ℹ️ 关于页面", font=("Arial", 18), bg="#FFF3E0").pack(pady=50)
        tk.Label(frame, text="版本: 1.0.0", bg="#FFF3E0").pack()
        return frame
    
    def create_nav(self):
        nav_frame = tk.Frame(self.master)
        nav_frame.pack(side=tk.BOTTOM, pady=10)
        
        tk.Button(nav_frame, text="数据", command=lambda: self.show_page(self.page1)).pack(side=tk.LEFT, padx=5)
        tk.Button(nav_frame, text="设置", command=lambda: self.show_page(self.page2)).pack(side=tk.LEFT, padx=5)
        tk.Button(nav_frame, text="关于", command=lambda: self.show_page(self.page3)).pack(side=tk.LEFT, padx=5)
    
    def show_page(self, page):
        # 隐藏所有页面
        self.page1.pack_forget()
        self.page2.pack_forget()
        self.page3.pack_forget()
        # 显示指定页面
        page.pack(fill=tk.BOTH, expand=True)

# 使用
root = tk.Tk()
app = MultiPageApp(root)
root.mainloop()

11. 样式与主题

11.1 使用ttk主题

import tkinter as tk
from tkinter import ttk

window = tk.Tk()
window.title("ttk主题演示")
window.geometry("400x400")

# 查看可用主题
themes = ttk.Style().theme_names()
print("可用主题:", themes)

# 选择主题
ttk.Style().theme_use("clam")  # 可选: default, alt, clam, vista, xpnative

# 创建组件
ttk.Label(window, text="ttk标签", font=("Arial", 12)).pack(pady=10)
ttk.Button(window, text="ttk按钮").pack(pady=5)
ttk.Entry(window, width=20).pack(pady=5)
ttk.Combobox(window, values=["选项1", "选项2"], width=18).pack(pady=5)

# 创建Frame
frame = ttk.LabelFrame(window, text="分组", padding=10)
frame.pack(pady=15, padx=10, fill=tk.X)

ttk.Label(frame, text="在Frame内的标签").pack()
ttk.Button(frame, text="在Frame内的按钮").pack(pady=5)

# 创建进度条
ttk.Label(window, text="进度条:").pack()
progress = ttk.Progressbar(window, mode="indeterminate", length=200)
progress.pack(pady=5)
progress.start()

# 样式自定义
style = ttk.Style()
style.configure("Custom.TButton", font=("Arial", 10, "bold"))
ttk.Button(window, text="自定义样式按钮", style="Custom.TButton").pack(pady=15)

window.mainloop()

11.2 常用样式配置

import tkinter as tk
from tkinter import ttk

style = ttk.Style()

# 配置按钮样式
style.configure(
    "TButton",
    padding=6,
    relief="flat",
    background="#4CAF50",
    font=("Arial", 10)
)

# 配置标签样式
style.configure(
    "TLabel",
    font=("Arial", 11),
    foreground="#333333"
)

# 配置Frame样式
style.configure(
    "TFrame",
    background="#f5f5f5"
)

# 配置LabelFrame样式
style.configure(
    "TLabelframe",
    background="#ffffff",
    relief="solid"
)

# 配置Treeview样式
style.configure(
    "Treeview",
    background="#ffffff",
    foreground="#333333",
    fieldbackground="#ffffff"
)
style.map(
    "Treeview",
    background=[("selected", "#4CAF50")],
    foreground=[("selected", "#ffffff")]
)

12. 实战项目

12.1 项目一:简易计算器

import tkinter as tk

class Calculator:
    def __init__(self, master):
        self.master = master
        self.master.title("简易计算器")
        self.master.geometry("300x400")
        
        self.current = ""
        self.create_widgets()
    
    def create_widgets(self):
        # 显示框
        self.display = tk.Entry(
            self.master, 
            font=("Arial", 24),
            bd=10,
            insertwidth=2,
            width=12,
            justify="right"
        )
        self.display.grid(row=0, column=0, columnspan=4, sticky="nsew")
        
        # 按钮布局
        buttons = [
            ("C", 1, 0), ("(", 1, 1), (")", 1, 2), ("÷", 1, 3),
            ("7", 2, 0), ("8", 2, 1), ("9", 2, 2), ("×", 2, 3),
            ("4", 3, 0), ("5", 3, 1), ("6", 3, 2), ("-", 3, 3),
            ("1", 4, 0), ("2", 4, 1), ("3", 4, 2), ("+", 4, 3),
            ("0", 5, 0), (".", 5, 1), ("⌫", 5, 2), ("=", 5, 3),
        ]
        
        for (text, row, col) in buttons:
            self.create_button(text, row, col)
    
    def create_button(self, text, row, col):
        if text == "=":
            cmd = self.calculate
            bg = "#4CAF50"
        elif text == "C":
            cmd = self.clear
            bg = "#f44336"
        elif text == "⌫":
            cmd = self.backspace
            bg = "#FF9800"
        elif text in "+-×÷":
            cmd = lambda t=text: self.click_operator(t)
            bg = "#607D8B"
        else:
            cmd = lambda t=text: self.click_number(t)
            bg = "#E0E0E0"
        
        btn = tk.Button(
            self.master,
            text=text,
            font=("Arial", 18),
            bg=bg,
            fg="white" if text in "=C⌫+-×÷" else "black",
            bd=3,
            command=cmd
        )
        btn.grid(row=row, column=col, sticky="nsew", padx=2, pady=2)
    
    def click_number(self, num):
        self.current += num
        self.display.delete(0, tk.END)
        self.display.insert(0, self.current)
    
    def click_operator(self, op):
        if self.current and self.current[-1] not in "+-×÷":
            self.current += op
        self.display.delete(0, tk.END)
        self.display.insert(0, self.current)
    
    def calculate(self):
        try:
            expr = self.current.replace("×", "*").replace("÷", "/")
            result = eval(expr)
            self.display.delete(0, tk.END)
            self.display.insert(0, str(result))
            self.current = str(result)
        except:
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.current = ""
    
    def clear(self):
        self.current = ""
        self.display.delete(0, tk.END)
    
    def backspace(self):
        self.current = self.current[:-1]
        self.display.delete(0, tk.END)
        self.display.insert(0, self.current)

# 运行
root = tk.Tk()
app = Calculator(root)
root.mainloop()

运行效果:

图片[15]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了使用Tkinter实现的简易计算器界面,包含数字按钮、运算符和显示区域。

12.2 项目二:待办事项应用

import tkinter as tk
from tkinter import messagebox
import json

class TodoApp:
    def __init__(self, master):
        self.master = master
        self.master.title("待办事项")
        self.master.geometry("400x500")
        
        self.todos = []
        self.load_todos()
        
        self.create_widgets()
        self.update_list()
    
    def create_widgets(self):
        # 标题
        tk.Label(
            self.master, 
            text="📝 待办事项", 
            font=("Arial", 20, "bold")
        ).pack(pady=10)
        
        # 输入框
        input_frame = tk.Frame(self.master)
        input_frame.pack(pady=10, padx=10, fill=tk.X)
        
        self.entry = tk.Entry(input_frame, font=("Arial", 12))
        self.entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        
        tk.Button(
            input_frame, 
            text="添加", 
            command=self.add_todo,
            bg="#4CAF50",
            fg="white",
            width=8
        ).pack(side=tk.LEFT)
        
        # 列表框
        self.listbox = tk.Listbox(
            self.master,
            font=("Arial", 12),
            height=15,
            selectmode=tk.SINGLE
        )
        self.listbox.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
        
        # 按钮栏
        btn_frame = tk.Frame(self.master)
        btn_frame.pack(pady=10)
        
        tk.Button(
            btn_frame, 
            text="✓ 完成", 
            command=self.complete_todo,
            width=10
        ).pack(side=tk.LEFT, padx=5)
        
        tk.Button(
            btn_frame, 
            text="✗ 删除", 
            command=self.delete_todo,
            width=10
        ).pack(side=tk.LEFT, padx=5)
        
        tk.Button(
            btn_frame, 
            text="💾 保存", 
            command=self.save_todos,
            width=10,
            bg="#2196F3",
            fg="white"
        ).pack(side=tk.LEFT, padx=5)
    
    def add_todo(self):
        text = self.entry.get().strip()
        if text:
            self.todos.append({"text": text, "done": False})
            self.entry.delete(0, tk.END)
            self.update_list()
    
    def complete_todo(self):
        try:
            idx = self.listbox.curselection()[0]
            self.todos[idx]["done"] = not self.todos[idx]["done"]
            self.update_list()
        except:
            messagebox.showwarning("提示", "请先选择一个事项")
    
    def delete_todo(self):
        try:
            idx = self.listbox.curselection()[0]
            del self.todos[idx]
            self.update_list()
        except:
            messagebox.showwarning("提示", "请先选择一个事项")
    
    def update_list(self):
        self.listbox.delete(0, tk.END)
        for todo in self.todos:
            prefix = "✓" if todo["done"] else "○"
            text = f"{prefix} {todo['text']}"
            if todo["done"]:
                text = f"✓ {todo['text']} (已完成)"
            self.listbox.insert(tk.END, text)
    
    def save_todos(self):
        with open("todos.json", "w", encoding="utf-8") as f:
            json.dump(self.todos, f, ensure_ascii=False)
        messagebox.showinfo("保存", "待办事项已保存!")
    
    def load_todos(self):
        try:
            with open("todos.json", "r", encoding="utf-8") as f:
                self.todos = json.load(f)
        except:
            self.todos = []

# 运行
root = tk.Tk()
app = TodoApp(root)
root.mainloop()

运行效果:

图片[16]-Python 进阶教程:Tkinter GUI 图形界面编程-小程博客

上图展示了待办事项应用界面,支持添加、完成和删除任务。

12.3 项目三:图片查看器

import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk

class ImageViewer:
    def __init__(self, master):
        self.master = master
        self.master.title("图片查看器")
        self.master.geometry("600x500")
        
        self.image = None
        self.photo = None
        
        self.create_widgets()
    
    def create_widgets(self):
        # 工具栏
        toolbar = tk.Frame(self.master)
        toolbar.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
        
        tk.Button(toolbar, text="📂 打开", command=self.open_image).pack(side=tk.LEFT, padx=5)
        tk.Button(toolbar, text="🔄 缩放", command=self.reset_zoom).pack(side=tk.LEFT, padx=5)
        tk.Button(toolbar, text="➕ 放大", command=self.zoom_in).pack(side=tk.LEFT, padx=5)
        tk.Button(toolbar, text="➖ 缩小", command=self.zoom_out).pack(side=tk.LEFT, padx=5)
        
        # 画布
        self.canvas = tk.Canvas(self.master, bg="#333333")
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 状态栏
        self.status = tk.Label(self.master, text="请打开图片", relief=tk.SUNKEN)
        self.status.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 绑定鼠标滚轮缩放
        self.canvas.bind("<MouseWheel>", self.on_mouse_wheel)
    
    def open_image(self):
        filename = filedialog.askopenfilename(
            title="选择图片",
            filetypes=[
                ("图片文件", "*.png *.jpg *.jpeg *.gif *.bmp"),
                ("所有文件", "*.*")
            ]
        )
        if filename:
            try:
                self.image = Image.open(filename)
                self.filename = filename
                self.scale = 1.0
                self.show_image()
                self.status.config(text=f"已打开: {filename}")
            except Exception as e:
                messagebox.showerror("错误", f"无法打开图片:\n{e}")
    
    def show_image(self):
        if self.image:
            # 计算缩放后的尺寸
            w, h = self.image.size
            new_w = int(w * self.scale)
            new_h = int(h * self.scale)
            
            # 缩放图片
            display_image = self.image.resize((new_w, new_h), Image.Resampling.LANCZOS)
            self.photo = ImageTk.PhotoImage(display_image)
            
            # 清空画布并显示图片
            self.canvas.delete("all")
            self.canvas.create_image(new_w//2, new_h//2, image=self.photo)
            
            # 更新状态
            self.status.config(
                text=f"尺寸: {w}x{h} | 缩放: {int(self.scale*100)}%"
            )
    
    def zoom_in(self):
        self.scale *= 1.2
        self.show_image()
    
    def zoom_out(self):
        self.scale /= 1.2
        self.show_image()
    
    def reset_zoom(self):
        self.scale = 1.0
        self.show_image()
    
    def on_mouse_wheel(self, event):
        if event.delta > 0:
            self.zoom_in()
        else:
            self.zoom_out()

# 运行
root = tk.Tk()
app = ImageViewer(root)
root.mainloop()

13. 常见问题与解决方案

13.1 问题排查表

问题原因解决方案
窗口不显示没有调用mainloop()添加window.mainloop()
组件不显示没有调用pack/grid/place添加布局管理器方法
输入框无法输入Entry组件被禁用设置state=tk.NORMAL
按钮command不响应函数调用写法错误command=self.func不带括号
中文显示乱码字体不支持中文使用支持中文的字体如”微软雅黑”
图片不显示路径错误或格式不支持检查路径,使用PIL加载图片
窗口闪退程序执行完自动退出在末尾调用mainloop()
Listbox选不中Selection事件绑定错误使用<<ListboxSelect>>事件

13.2 常见错误代码

# ❌ 错误:command写成函数调用
button = tk.Button(text="点击", command=on_click())  # 会立即执行

# ✅ 正确:command写成函数引用
button = tk.Button(text="点击", command=on_click)

# ❌ 错误:忘记pack
label = tk.Label(text="Hello")
# 没有调用pack(),组件不会显示

# ✅ 正确:调用pack
label.pack()

# ❌ 错误:在循环中创建多个mainloop
for i in range(5):
    root = tk.Tk()
    root.mainloop()  # 错误做法

# ✅ 正确:只创建一个主窗口
root = tk.Tk()
# ... 添加所有组件
root.mainloop()

# ❌ 错误:忘记self导致变量作用域问题
def create_widgets(self):
    label = tk.Label(...)  # 错误:应该是self.label
    label.pack()

14. 最佳实践

14.1 代码组织结构

import tkinter as tk
from tkinter import ttk, messagebox, filedialog

class Application(tk.Tk):
    """应用程序主类"""
    
    def __init__(self):
        super().__init__()
        self.title("我的应用")
        self.geometry("800x600")
        
        self.create_widgets()
        self.create_menu()
        self.create_layout()
    
    def create_widgets(self):
        """创建所有组件"""
        pass
    
    def create_menu(self):
        """创建菜单"""
        pass
    
    def create_layout(self):
        """设置布局"""
        pass
    
    def on_open(self):
        """打开文件"""
        pass
    
    def on_save(self):
        """保存文件"""
        pass

if __name__ == "__main__":
    app = Application()
    app.mainloop()

14.2 性能优化建议

优化项方法效果
减少组件创建复用组件而非重建提升响应速度
使用ttk组件替换tk组件为ttk更美观、性能更好
延迟更新使用after()批量更新减少卡顿
图片缓存预加载并缓存图片加快显示
批量绑定同一事件类型绑定到容器简化代码

14.3 安全注意事项

# 1. 输入验证
def validate_input(text):
    if not text.isdigit():
        return False
    value = int(text)
    return 0 <= value <= 100

# 2. 防止SQL注入(如果涉及数据库)
def safe_query(user_input):
    # 使用参数化查询
    cursor.execute("SELECT * FROM users WHERE name = ?", (user_input,))

# 3. 文件路径安全
def safe_open_file(filepath):
    import os
    real_path = os.path.realpath(filepath)
    if not real_path.startswith(ALLOWED_DIR):
        return None
    return open(real_path, 'r')

附录

A. 快捷键参考

快捷键功能适用场景
Ctrl+N新建文件操作
Ctrl+O打开文件操作
Ctrl+S保存文件操作
Ctrl+Z撤销文本编辑
Ctrl+C复制通用
Ctrl+V粘贴通用
Escape取消/关闭通用

B. 颜色代码速查

颜色名十六进制效果
红色#FF6B6B🔴
蓝色#4ECDC4🔵
绿色#45B7D1🟢
黄色#FFEAA7🟡
紫色#A29BFE🟣
橙色#FDCB6E🟠
灰色#636E72

参考资料


📝 文档版本: 1.0 🔧 最后更新: 2024年 💡 提示: 建议配合Python IDLE或IDE实际运行代码进行学习!

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容