第16章 图形程序 - 让程序有“面子“
引言:从黑白世界到彩色世界
想象一下,如果你一直在用这样的方式和使用电脑程序:
请输入你的名字:小明
请输入你的年龄:12
你好,小明!你今年12岁了。
这是我们在前面章节中一直使用的命令行程序(Command Line Interface,简称CLI)。它的特点是:
- 只能输入文字
- 只能显示文字
- 需要记住各种命令
- 界面简陋(黑底白字)
但是现在,你用的QQ、微信、王者荣耀、我的世界……这些程序是什么样子的?
- 有漂亮的窗口
- 可以点击按钮
- 可以在输入框里打字
- 可以看到图片和颜色
- 可以用鼠标操作
这种程序叫图形界面程序(Graphical User Interface,简称GUI)!
什么是GUI?
GUI(Graphical User Interface)就是图形用户界面。让我们通过对比来理解:
| 特性 | 命令行程序(CLI) | 图形界面程序(GUI) |
|---|---|---|
| 外观 | 黑底白字,只有文字 | 彩色窗口,有图片、按钮、图标 |
| 操作方式 | 只能用键盘输入命令 | 可以用鼠标点击、拖拽 |
| 使用难度 | 需要记住命令 | 直观易懂,看图标就知道功能 |
| 例子 | 我们之前的所有程序 | QQ、微信、游戏、浏览器 |
为什么学习GUI程序?
学习制作图形界面程序,你将能够:
-
制作真正“像样“的软件
- 不再只是黑白的文字界面
- 可以有漂亮的按钮、输入框、图片
- 让你的程序看起来更专业
-
改善用户体验
- 用户不需要记住命令
- 看到按钮就知道能做什么
- 操作更直观、更方便
-
将之前的程序“升级“
- 把第14章的命令行课表查询程序改成带按钮的
- 把计算器程序改成有按钮和显示屏幕的
- 把猜数字游戏改成有界面的
-
理解日常软件的原理
- QQ的聊天窗口是怎么做出来的?
- 游戏的设置界面是怎么设计的?
- 学完这一章,你就知道答案了!
本章学习路线
本章将教你使用tkinter库制作图形界面程序,同时融入几何和坐标知识:
第1步:认识tkinter库 - Python自带的GUI工具
↓
第2步:复习数学坐标知识 - 窗口坐标系统
↓
第3步:创建第一个窗口 - 设置大小和位置
↓
第4步:添加组件 - 按钮、输入框、标签(运用坐标知识)
↓
第5步:布局管理 - 让组件排列整齐(运用几何知识)
↓
第6步:事件处理 - 让按钮"动"起来
↓
第7步:综合项目 - 改写CLI程序为GUI版本
👨🏫 给家长的小贴士
- GUI是现代软件的标准: 几乎所有现代软件都使用图形界面
- 培养用户思维: 让孩子思考“怎么让用户更方便地使用程序“
- 激发创造力: 图形界面可以自由设计颜色、布局,孩子会很有成就感
- 实际应用: 可以制作家庭记账本、学习计划表等实用工具
- 本章重点融入的数学知识:
- 坐标系: 计算机窗口的坐标原点在左上角(与数学坐标系不同)
- 位置和尺寸: 组件的(x, y)位置,宽度width,高度height
- 面积计算: 窗口面积 = 宽 × 高
- 几何图形: 矩形、正方形在界面布局中的应用
- 本章融入的计算机知识:
- 显卡和显示器: 图形如何显示在屏幕上
- 事件驱动: 点击按钮如何触发程序执行
- CPU的中断机制: 计算机如何响应鼠标和键盘操作
tkinter是什么?
tkinter是Python自带的一个图形界面库。它的名字来源于:
- tk: 一个著名的图形界面工具包(Tool Kit)
- inter: interface(界面)的缩写
- t: 表示这是Tk的Python接口( Tcl/Tk 的Python接口)
为什么要用tkinter?
- 免费且内置:Python安装时就自带了,不需要额外安装
- 简单易学:代码简洁,容易上手
- 功能够用:可以制作常见的界面元素
- 跨平台:在Windows、Mac、Linux上都能运行
tkinter能做什么?
- ✅ 创建窗口
- ✅ 添加按钮
- ✅ 添加输入框
- ✅ 添加文字标签
- ✅ 添加图片
- ✅ 添加下拉菜单
- ✅ 添加复选框和单选按钮
- ✅ 添加滑动条
- ✅ ……还有很多其他组件
给家长的小贴士
- GUI是现代软件的标准:几乎所有现代软件都使用图形界面
- 培养用户思维:让孩子思考“怎么让用户更方便地使用程序“
- 激发创造力:图形界面可以自由设计颜色、布局,孩子会很有成就感
- 实际应用:可以制作家庭记账本、学习计划表等实用工具
- 学习曲线:GUI比命令行程序复杂一些,需要更多耐心
- 建议:先让孩子熟悉一个简单例子,再鼓励他设计自己的界面
16.1 第一个窗口程序
16.1.1 最简单的窗口
让我们从最简单的开始——创建一个空白窗口!
# 导入tkinter库
import tkinter as tk
# 创建主窗口
root = tk.Tk()
# 进入消息循环(让窗口一直显示)
root.mainloop()
运行结果: 弹出一个空白窗口!
代码解释:
-
import tkinter as tk- 导入tkinter库
as tk表示给tkinter起个简短的别名,以后用tk代替tkinter
-
root = tk.Tk()- 创建一个主窗口
Tk()是创建主窗口的函数root是这个窗口的名字(你可以叫它window或main_window)
-
root.mainloop()- 进入消息循环
- 这是最重要的一行!
- 让窗口一直显示,等待用户操作
- 如果没有这一行,窗口会一闪而过
小知识:什么是“消息循环“?
想象一下你开了一家店:
root = tk.Tk():把店面装修好,准备开门root.mainloop():你站在店门口,一直等待顾客进来
- 如果顾客来了(点击按钮、输入文字等),你就处理顾客的需求
- 如果没有顾客,你就继续等待
- 如果没有这一步,店开一下就关门了!
16.1.2 给窗口起个名字
现在我们的窗口标题是默认的“tk“,让我们改个名字:
import tkinter as tk
root = tk.Tk()
# 设置窗口标题
root.title("我的第一个GUI程序")
root.mainloop()
运行结果: 窗口标题变成了“我的第一个GUI程序“!
16.1.3 设置窗口大小
窗口默认大小可能不太合适,让我们设置一下:
import tkinter as tk
root = tk.Tk()
root.title("我的第一个GUI程序")
# 设置窗口大小(宽x高)
root.geometry("400x300")
root.mainloop()
运行结果: 窗口变成了400像素宽、300像素高!
注意:
geometry的意思是“几何形状“"400x300"中的x是字母x,不是乘号!- 单位是像素(Pixel,电脑屏幕最小的显示单位)
16.1.4 综合示例:漂亮的窗口
import tkinter as tk
root = tk.Tk()
root.title("我的第一个GUI程序")
root.geometry("500x400")
# TODO: 后面我们会在这里添加按钮、输入框等组件
root.mainloop()
⚠️ 常见错误
错误1:忘记mainloop()
import tkinter as tk root = tk.Tk() # 忘记写 root.mainloop()结果:窗口一闪而过,或者根本不显示
错误2:大小写成乘号
root.geometry(400x300) # 错误!x会被当作变量名正确写法:
root.geometry("400x300")(必须加引号,且x是字母)
🎮 实践练习1:创建你的第一个窗口
任务:创建一个窗口,满足以下要求:
- 标题为:“Python图形界面”
- 大小为:600×400
- 尝试修改大小,看看不同尺寸的效果
提示:使用
title()和geometry()方法🔍 查看答案
import tkinter as tk root = tk.Tk() root.title("Python图形界面") root.geometry("600x400") root.mainloop()
16.2 认识计算机坐标系 📐
在开始添加组件之前,让我们先学习计算机的坐标系,这对放置组件非常重要!
16.2.1 计算机坐标系 vs 数学坐标系
你在数学课上学过平面直角坐标系:
- 原点: 在左下角
- x轴: 向右为正方向
- y轴: 向上为正方向
- 坐标: (x, y),x是横坐标,y是纵坐标
数学坐标系示例:
y↑
|
4 | • (3, 4)
3 |
2 |
1 | • (1, 1)
0---+---+---+---+---→x
0 1 2 3 4
但是,计算机的坐标系完全不同!
16.2.2 计算机窗口坐标系
计算机坐标系的特点:
- 原点: 在左上角(记住这个重要差异!)
- x轴: 向右为正方向(和数学一样)
- y轴: 向下为正方向(和数学相反!)
- 单位: 像素(Pixel)
计算机坐标系示例:
0 1 2 3 4 →x
0---+---+---+---+---
1 | • (1, 1)
2 |
3 | • (3, 3)
4 |
↓y
关键差异:
- 数学坐标系:y向上,计算机坐标系:y向下
- 数学坐标系:原点在左下,计算机坐标系:原点在左上
为什么计算机坐标系是这样的?
- 显示器扫描是从左上角开始的(像我们看书,从左上到右下)
- 这样设计符合西方文字的阅读习惯(从上到下,从左到右)
👨🏫 给家长的小贴士
- 类比方法: 用阅读顺序解释为什么y轴向下(看书从第一行开始,往下看)
- 对比记忆: 在纸上画两个坐标系对比,加深印象
- 实际演示: 在纸上画图,然后思考在计算机上如何实现
- 常见错误: 孩子容易混淆两个坐标系,需要多次强调“左上角是原点“
16.2.3 窗口的坐标和尺寸
让我们用代码理解窗口的坐标和尺寸:
import tkinter as tk
root = tk.Tk()
root.title("窗口坐标示例")
# 设置窗口大小(宽x高)
root.geometry("400x300")
print(f"窗口宽度: {root.winfo_width()}") # 400
print(f"窗口高度: {root.winfo_height()}") # 300
# 注意:窗口创建后,需要更新才能获取正确尺寸
root.update()
print(f"更新后宽度: {root.winfo_width()}")
print(f"更新后高度: {root.winfo_height()}")
root.mainloop()
代码解析:
geometry("400x300"): 设置窗口宽400像素,高300像素winfo_width(): 获取窗口的当前宽度winfo_height(): 获取窗口的当前高度update(): 强制窗口更新,确保获取到正确的尺寸
16.2.4 组件的位置坐标
当我们添加按钮、标签等组件时,需要指定它们的位置。
位置参数:
x: 组件左上角的x坐标(从窗口左边开始)y: 组件左上角的y坐标(从窗口上边开始)width: 组件的宽度height: 组件的高度
示例:
import tkinter as tk
root = tk.Tk()
root.title("组件位置示例")
root.geometry("400x300")
# 添加一个标签,指定位置(x=50, y=100)
label = tk.Label(root, text="我在哪里?", bg="yellow")
label.place(x=50, y=100, width=200, height=30)
root.mainloop()
代码解析:
x=50: 标签左边距离窗口左边50像素y=100: 标签上边距离窗口上边100像素width=200: 标签宽度200像素height=30: 标签高度30像素
可视化:
窗口(400x300)
┌────────────────────────────┐
│ ↑y │
│ │ │
│ │ ┌──────────┐ │
│100 │黄色标签 │(200x30) │
│ │ └──────────┘ │
│ │ │
│ └─→x │
│ 50 │
└────────────────────────────┘
16.2.5 坐标计算练习
让我们做一些数学练习,巩固坐标的概念!
练习1: 计算组件位置
窗口大小是600×400,你想把一个按钮放在:
- 窗口的正中央
- 按钮大小是100×50
数学计算:
窗口宽度 = 600,窗口高度 = 400
按钮宽度 = 100,按钮高度 = 50
正中央的x坐标 = (窗口宽度 - 按钮宽度) / 2
= (600 - 100) / 2
= 500 / 2
= 250
正中央的y坐标 = (窗口高度 - 按钮高度) / 2
= (400 - 50) / 2
= 350 / 2
= 175
所以按钮坐标是 (250, 175)
Python代码验证:
import tkinter as tk
root = tk.Tk()
root.title("居中按钮")
root.geometry("600x400")
# 计算居中位置
window_width = 600
window_height = 400
button_width = 100
button_height = 50
center_x = (window_width - button_width) / 2 # 250
center_y = (window_height - button_height) / 2 # 175
# 创建按钮
button = tk.Button(root, text="我在正中央!", bg="lightblue")
button.place(x=center_x, y=center_y, width=button_width, height=button_height)
print(f"按钮坐标: ({center_x}, {center_y})")
root.mainloop()
练习2: 计算窗口面积和组件面积
import tkinter as tk
root = tk.Tk()
root.title("面积计算")
root.geometry("500x400")
# 窗口面积
window_area = 500 * 400
print(f"窗口面积: {window_area} 平方像素")
# 添加3个按钮
btn1 = tk.Button(root, text="按钮1", bg="red")
btn1.place(x=50, y=50, width=100, height=40)
btn2 = tk.Button(root, text="按钮2", bg="green")
btn2.place(x=200, y=100, width=120, height=50)
btn3 = tk.Button(root, text="按钮3", bg="blue")
btn3.place(x=100, y=250, width=150, height=60)
# 计算按钮总面积
btn1_area = 100 * 40 # 4000
btn2_area = 120 * 50 # 6000
btn3_area = 150 * 60 # 9000
total_btn_area = btn1_area + btn2_area + btn3_area
print(f"按钮1面积: {btn1_area}")
print(f"按钮2面积: {btn2_area}")
print(f"按钮3面积: {btn3_area}")
print(f"按钮总面积: {total_btn_area}")
print(f"按钮占窗口比例: {total_btn_area / window_area * 100:.1f}%")
root.mainloop()
运行结果:
窗口面积: 200000 平方像素
按钮1面积: 4000
按钮2面积: 6000
按钮3面积: 9000
按钮总面积: 19000
按钮占窗口比例: 9.5%
👨🏫 给家长的小贴士
- 数学融入: GUI编程是复习数学知识(坐标、面积、比例)的好机会
- 可视化: 比起纸上的题目,GUI让学生能直观看到计算结果
- 实际应用: 问孩子“如果让你设计一个登录界面,按钮应该放哪里?“
- 难度递进: 从简单的位置计算开始,逐步到复杂的布局
- 鼓励调试: 让孩子修改坐标数值,看看组件位置如何变化
16.2.6 坐标系对比总结
| 特性 | 数学坐标系 | 计算机坐标系 |
|---|---|---|
| 原点位置 | 左下角 | 左上角 |
| x轴方向 | 向右为正 | 向右为正 |
| y轴方向 | 向上为正 | 向下为正 |
| 坐标表示 | (x, y) | (x, y) |
| 常见用途 | 数学函数图像 | 窗口、网页布局 |
🎯 实践练习2:坐标计算练习
任务: 创建一个窗口(600×400),完成以下组件的放置:
- 标签“标题“:放在窗口正上方(x=200, y=20,宽200,高30)
- 按钮“确定“:放在窗口正中央,大小100×40
- 按钮“取消“:放在“确定“按钮右边50像素处
- 计算“确定“按钮的坐标(x, y)
- 计算两个按钮总共占多少面积
答案:
🔍 查看答案
import tkinter as tk root = tk.Tk() root.title("坐标练习") root.geometry("600x400") # 1. 标题 title_label = tk.Label(root, text="用户登录", bg="lightyellow", font=("Arial", 16)) title_label.place(x=200, y=20, width=200, height=30) # 2. 确定按钮(正中央) btn_width = 100 btn_height = 40 window_width = 600 window_height = 400 ok_x = (window_width - btn_width) / 2 # 250 ok_y = (window_height - btn_height) / 2 # 180 ok_btn = tk.Button(root, text="确定", bg="lightgreen") ok_btn.place(x=ok_x, y=ok_y, width=btn_width, height=btn_height) print(f"确定按钮坐标: ({ok_x}, {ok_y})") # 3. 取消按钮(右边50像素) cancel_x = ok_x + btn_width + 50 # 250 + 100 + 50 = 400 cancel_y = ok_y # 和确定按钮同一行 cancel_btn = tk.Button(root, text="取消", bg="lightcoral") cancel_btn.place(x=cancel_x, y=cancel_y, width=btn_width, height=btn_height) # 4. 计算总面积 one_btn_area = btn_width * btn_height # 4000 two_btn_area = one_btn_area * 2 # 8000 print(f"两个按钮总面积: {two_btn_area} 平方像素") root.mainloop()
16.3 常用组件:按钮、标签和输入框
窗口创建好了,但里面空空如也!让我们添加一些组件(Widget)。
什么是组件? 组件就是窗口里的各种元素,比如:
- 按钮(Button)
- 标签(Label,显示文字)
- 输入框(Entry)
- 文本框(Text)
- 等等……
16.2.1 标签(Label)- 显示文字
标签用来在窗口上显示文字或图片。
import tkinter as tk
root = tk.Tk()
root.title("标签示例")
root.geometry("300x200")
# 创建一个标签
label = tk.Label(root, text="你好,这是我的第一个标签!")
# 把标签显示到窗口上
label.pack()
root.mainloop()
运行结果: 窗口中显示了一行文字:“你好,这是我的第一个标签!”
代码解释:
-
tk.Label(root, text="...")root:表示这个标签要放在哪个窗口里text="...":标签上显示的文字
-
label.pack()- 这一行很重要!
- 把标签“打包“放到窗口上
- 如果不写这一行,标签不会显示
🎯 类比时间
想象你在布置房间:
tk.Label():在纸上画出装饰品.pack():把这个装饰品真正贴到墙上
16.2.2 按钮(Button)- 可以点击
按钮是最常用的组件之一,点击后可以触发某个操作。
import tkinter as tk
root = tk.Tk()
root.title("按钮示例")
root.geometry("300x200")
# 创建一个按钮
button = tk.Button(root, text="点击我")
# 把按钮显示到窗口上
button.pack()
root.mainloop()
运行结果: 窗口中显示了一个按钮,上面写着“点击我“,你可以用鼠标点击它!(虽然现在点击不会发生什么)
16.2.3 输入框(Entry)- 输入文字
输入框让用户可以输入文字。
import tkinter as tk
root = tk.Tk()
root.title("输入框示例")
root.geometry("300x200")
# 创建一个标签作为提示
label = tk.Label(root, text="请输入你的名字:")
label.pack()
# 创建一个输入框
entry = tk.Entry(root)
entry.pack()
root.mainloop()
运行结果:
- 上面一行文字:“请输入你的名字:”
- 下面一个白色的输入框,你可以在里面打字!
16.2.4 让按钮“动“起来:事件处理
现在按钮能点击,但点击后什么都没发生。让我们让按钮点击后做点事情!
import tkinter as tk
# 定义一个函数(点击按钮时会执行这个函数)
def on_button_click():
print("按钮被点击了!")
root = tk.Tk()
root.title("按钮点击示例")
root.geometry("300x200")
# 创建按钮,点击时执行on_button_click函数
button = tk.Button(root, text="点击我", command=on_button_click)
button.pack()
root.mainloop()
运行结果: 每次点击按钮,在命令行(终端/黑窗口)中会输出:“按钮被点击了!”
代码解释:
-
def on_button_click():- 定义了一个函数
- 这个函数包含了点击按钮时要执行的代码
-
command=on_button_clickcommand是Button的一个参数- 它告诉按钮:被点击时执行哪个函数
- 注意:函数名后面不要加括号
()
⚠️ 重要提醒
# ✅ 正确写法 button = tk.Button(root, text="点击我", command=on_button_click) # ❌ 错误写法 button = tk.Button(root, text="点击我", command=on_button_click())为什么不能加括号?
- 加了括号意味着“立刻执行这个函数“
- 不加括号意味着“把这个函数的名字告诉按钮,等点击时再执行“
16.2.5 实用示例:获取输入框的内容
让我们做一个更有用的例子:在输入框输入名字,点击按钮后显示问候语!
import tkinter as tk
def say_hello():
# 获取输入框的内容
name = entry.get()
# 创建一个新标签显示问候语
result_label = tk.Label(root, text=f"你好,{name}!")
result_label.pack()
root = tk.Tk()
root.title("问候程序")
root.geometry("300x200")
# 提示标签
label = tk.Label(root, text="请输入你的名字:")
label.pack()
# 输入框
entry = tk.Entry(root)
entry.pack()
# 按钮
button = tk.Button(root, text="问候", command=say_hello)
button.pack()
root.mainloop()
运行结果:
- 在输入框输入名字,比如“小明“
- 点击“问候“按钮
- 下面会显示:“你好,小明!”
代码解释:
-
entry.get()- 获取输入框中用户输入的内容
- 返回一个字符串
-
每次点击按钮,都会创建一个新标签显示问候语
🎮 实践练习2:制作一个简单的计算器
任务:制作一个能计算两个数之和的程序
要求:
- 两个输入框:输入第一个数和第二个数
- 一个按钮:点击时计算和
- 一个标签:显示计算结果
提示:
- 使用两个Entry组件
- 使用
entry.get()获取输入- 注意:
get()返回的是字符串,需要用int()转换为数字🔍 查看答案
import tkinter as tk def calculate_sum(): # 获取两个输入框的值 num1 = entry1.get() num2 = entry2.get() # 转换为整数并计算 result = int(num1) + int(num2) # 显示结果 result_label.config(text=f"结果:{result}") root = tk.Tk() root.title("加法计算器") root.geometry("300x200") # 第一个数 label1 = tk.Label(root, text="第一个数:") label1.pack() entry1 = tk.Entry(root) entry1.pack() # 第二个数 label2 = tk.Label(root, text="第二个数:") label2.pack() entry2 = tk.Entry(root) entry2.pack() # 计算按钮 button = tk.Button(root, text="计算", command=calculate_sum) button.pack() # 结果标签 result_label = tk.Label(root, text="结果:") result_label.pack() root.mainloop()进阶挑战:
- 如果用户输入的不是数字,程序会出错吗?如何改进?
- 提示:使用
try-except捕获错误
16.3 布局管理:让组件排列整齐
现在你会发现一个问题:每次用.pack(),组件都是自动从上往下排。如果我们想要更灵活的布局呢?
tkinter提供了三种布局管理器:
- pack:按顺序排列(简单)
- grid:网格排列(灵活)
- place:精确位置(精确)
16.3.1 pack布局 - 简单排列
pack是最简单的布局方式,组件会按顺序从上到下、从左到右排列。
import tkinter as tk
root = tk.Tk()
root.title("pack布局示例")
root.geometry("300x200")
label1 = tk.Label(root, text="第一个标签")
label1.pack()
label2 = tk.Label(root, text="第二个标签")
label2.pack()
label3 = tk.Label(root, text="第三个标签")
label3.pack()
root.mainloop()
运行结果: 三个标签从上到下排列
pack的常用参数:
# 从顶部开始排列
label.pack(side="top")
# 从底部开始排列
label.pack(side="bottom")
# 从左边开始排列
label.pack(side="left")
# 从右边开始排列
label.pack(side="right")
# 设置外部间距(与其他组件的距离)
label.pack(padx=10, pady=10) # x方向10像素,y方向10像素
# 设置内部填充(组件内容与边框的距离)
label.pack(ipadx=5, ipady=5)
16.3.2 grid布局 - 网格排列
grid让窗口像一个表格,可以指定组件放在哪一行、哪一列。
import tkinter as tk
root = tk.Tk()
root.title("grid布局示例")
root.geometry("300x200")
# 第1行,第1列
label1 = tk.Label(root, text="用户名:")
label1.grid(row=0, column=0)
# 第1行,第2列
entry1 = tk.Entry(root)
entry1.grid(row=0, column=1)
# 第2行,第1列
label2 = tk.Label(root, text="密码:")
label2.grid(row=1, column=0)
# 第2行,第2列
entry2 = tk.Entry(root)
entry2.grid(row=1, column=1)
# 第3行,跨两列
button = tk.Button(root, text="登录")
button.grid(row=2, column=0, columnspan=2)
root.mainloop()
运行结果:
用户名: [输入框]
密码: [输入框]
[ 登录按钮 ]
代码解释:
row=0, column=0:放在第0行、第0列(注意:从0开始计数!)columnspan=2:跨2列(按钮横跨两列)
💡 什么时候用pack,什么时候用grid?
用pack:
- 简单的从上到下排列
- 不需要精确控制位置
用grid:
- 需要表格式的布局
- 需要精确控制行和列
- 比如登录表单(标签和输入框对齐)
🎮 实践练习3:使用grid布局制作登录界面
任务:使用grid布局制作一个登录界面
要求:
- 用户名标签和输入框(第1行)
- 密码标签和输入框(第2行)
- 登录按钮(第3行,跨两列居中)
🔍 查看答案
import tkinter as tk def login(): username = entry_username.get() password = entry_password.get() result_label.config(text=f"用户名:{username}\n密码:{password}") root = tk.Tk() root.title("登录界面") root.geometry("300x200") # 用户名 label_username = tk.Label(root, text="用户名:") label_username.grid(row=0, column=0, padx=5, pady=5) entry_username = tk.Entry(root) entry_username.grid(row=0, column=1, padx=5, pady=5) # 密码 label_password = tk.Label(root, text="密码:") label_password.grid(row=1, column=0, padx=5, pady=5) entry_password = tk.Entry(root, show="*") # 显示为星号 entry_password.grid(row=1, column=1, padx=5, pady=5) # 登录按钮 button_login = tk.Button(root, text="登录", command=login) button_login.grid(row=2, column=0, columnspan=2, pady=10) # 结果标签 result_label = tk.Label(root, text="") result_label.grid(row=3, column=0, columnspan=2) root.mainloop()新知识点:
show="*":让输入框显示为星号(用于密码输入)padx=5, pady=5:设置组件的外部间距
16.3.3 place布局 - 精确定位
place可以精确指定组件的位置(不常用,了解一下即可)。
import tkinter as tk
root = tk.Tk()
root.title("place布局示例")
root.geometry("300x200")
# 在坐标(100, 50)处放置标签
label = tk.Label(root, text="精确位置的标签")
label.place(x=100, y=50)
root.mainloop()
16.4 更多常用组件
除了按钮、标签和输入框,tkinter还有很多其他有用的组件。
16.4.1 文本框(Text)- 多行文本
**输入框(Entry)**只能输入一行,**文本框(Text)**可以输入多行。
import tkinter as tk
def show_text():
# 获取文本框内容
content = text.get("1.0", "end") # 从第1行第0列到末尾
print(content)
root = tk.Tk()
root.title("文本框示例")
root.geometry("400x300")
# 创建文本框
text = tk.Text(root, width=40, height=10)
text.pack()
# 创建按钮
button = tk.Button(root, text="显示内容", command=show_text)
button.pack()
root.mainloop()
运行结果:
- 一个大的文本框,可以输入多行文字
- 点击按钮后,在终端显示文本框内容
代码解释:
width=40, height=10:文本框宽40个字符,高10行text.get("1.0", "end"):获取从第1行第0列到末尾的所有内容
16.4.2 复选框(Checkbutton)
复选框让用户选择“是/否“或“选中/不选中“。
import tkinter as tk
def show_hobbies():
if var_music.get() == 1:
print("你喜欢音乐")
if var_sports.get() == 1:
print("你喜欢运动")
if var_reading.get() == 1:
print("你喜欢阅读")
root = tk.Tk()
root.title("复选框示例")
root.geometry("300x200")
# 创建变量存储复选框状态
var_music = tk.IntVar()
var_sports = tk.IntVar()
var_reading = tk.IntVar()
# 创建复选框
check_music = tk.Checkbutton(root, text="音乐", variable=var_music)
check_music.pack()
check_sports = tk.Checkbutton(root, text="运动", variable=var_sports)
check_sports.pack()
check_reading = tk.Checkbutton(root, text="阅读", variable=var_reading)
check_reading.pack()
# 按钮
button = tk.Button(root, text="确定", command=show_hobbies)
button.pack()
root.mainloop()
代码解释:
tk.IntVar():创建一个整数变量variable=var_music:把复选框和变量绑定var_music.get() == 1:如果复选框被选中,值为1,否则为0
16.4.3 单选按钮(Radiobutton)
单选按钮让用户从多个选项中选一个。
import tkinter as tk
def show_grade():
grade = var_grade.get()
print(f"你选择的年级是:{grade}")
root = tk.Tk()
root.title("单选按钮示例")
root.geometry("300x200")
# 创建变量存储选项
var_grade = tk.StringVar()
var_grade.set("一年级") # 默认值
# 创建单选按钮
radio1 = tk.Radiobutton(root, text="一年级", variable=var_grade, value="一年级")
radio1.pack()
radio2 = tk.Radiobutton(root, text="二年级", variable=var_grade, value="二年级")
radio2.pack()
radio3 = tk.Radiobutton(root, text="三年级", variable=var_grade, value="三年级")
radio3.pack()
# 按钮
button = tk.Button(root, text="确定", command=show_grade)
button.pack()
root.mainloop()
代码解释:
tk.StringVar():创建一个字符串变量value="一年级":这个选项代表的值- 所有单选按钮使用同一个
variable,这样它们就会互斥(只能选一个)
🎮 实践练习4:制作调查问卷
任务:制作一个调查问卷
要求:
- 姓名(输入框)
- 年级(单选按钮:一年级/二年级/三年级/四年级/五年级/六年级)
- 爱好(复选框:阅读/运动/音乐/绘画/游戏)
- 提交按钮(点击后显示用户的选择)
🔍 查看答案
import tkinter as tk def submit(): name = entry_name.get() grade = var_grade.get() hobbies = [] if var_reading.get() == 1: hobbies.append("阅读") if var_sports.get() == 1: hobbies.append("运动") if var_music.get() == 1: hobbies.append("音乐") if var_painting.get() == 1: hobbies.append("绘画") if var_games.get() == 1: hobbies.append("游戏") result = f"姓名:{name}\n年级:{grade}\n爱好:{', '.join(hobbies)}" result_label.config(text=result) root = tk.Tk() root.title("调查问卷") root.geometry("400x500") # 姓名 label_name = tk.Label(root, text="姓名:") label_name.pack(pady=5) entry_name = tk.Entry(root) entry_name.pack(pady=5) # 年级 label_grade = tk.Label(root, text="年级:") label_grade.pack(pady=5) var_grade = tk.StringVar() var_grade.set("一年级") grades = ["一年级", "二年级", "三年级", "四年级", "五年级", "六年级"] for g in grades: radio = tk.Radiobutton(root, text=g, variable=var_grade, value=g) radio.pack() # 爱好 label_hobbies = tk.Label(root, text="爱好(可多选):") label_hobbies.pack(pady=5) var_reading = tk.IntVar() var_sports = tk.IntVar() var_music = tk.IntVar() var_painting = tk.IntVar() var_games = tk.IntVar() check_reading = tk.Checkbutton(root, text="阅读", variable=var_reading) check_reading.pack() check_sports = tk.Checkbutton(root, text="运动", variable=var_sports) check_sports.pack() check_music = tk.Checkbutton(root, text="音乐", variable=var_music) check_music.pack() check_painting = tk.Checkbutton(root, text="绘画", variable=var_painting) check_painting.pack() check_games = tk.Checkbutton(root, text="游戏", variable=var_games) check_games.pack() # 提交按钮 button_submit = tk.Button(root, text="提交", command=submit) button_submit.pack(pady=10) # 结果 result_label = tk.Label(root, text="") result_label.pack(pady=10) root.mainloop()新知识点:
- 使用循环创建多个单选按钮
', '.join(hobbies):把列表用逗号连接成字符串
16.5 综合项目:改写命令行程序为GUI版本
现在我们已经学习了tkinter的基本知识,让我们把之前的命令行程序改写成图形界面版本!
16.5.1 项目选择:猜数字游戏
你还记得第7章(条件语句)中的猜数字游戏吗?
原版(命令行版本):
import random
secret = random.randint(1, 100)
guess = 0
while guess != secret:
guess = int(input("猜一个1-100的数字:"))
if guess > secret:
print("太大了!")
elif guess < secret:
print("太小了!")
else:
print("恭喜你,猜对了!")
改版(GUI版本):
import random
import tkinter as tk
from tkinter import messagebox
def check_guess():
# 获取用户输入
user_input = entry_guess.get()
# 检查是否输入了数字
if not user_input:
messagebox.showwarning("提示", "请输入一个数字!")
return
try:
guess = int(user_input)
except ValueError:
messagebox.showerror("错误", "请输入有效的数字!")
return
# 检查数字范围
if guess < 1 or guess > 100:
messagebox.showwarning("提示", "请输入1-100之间的数字!")
return
# 检查猜测结果
global attempts
attempts += 1
if guess > secret:
result_label.config(text="太大了!再试一次", fg="red")
elif guess < secret:
result_label.config(text="太小了!再试一次", fg="blue")
else:
result_label.config(text=f"恭喜你猜对了!答案就是{secret}!\n你用了{attempts}次。", fg="green")
messagebox.showinfo("成功", f"恭喜你猜对了!\n答案:{secret}\n尝试次数:{attempts}")
restart_game()
def restart_game():
global secret, attempts
secret = random.randint(1, 100)
attempts = 0
result_label.config(text="游戏已重新开始!请猜1-100的数字", fg="black")
entry_guess.delete(0, tk.END)
# 初始化游戏
secret = random.randint(1, 100)
attempts = 0
# 创建主窗口
root = tk.Tk()
root.title("猜数字游戏")
root.geometry("400x300")
# 标题
title_label = tk.Label(root, text="猜数字游戏(1-100)", font=("Arial", 16))
title_label.pack(pady=10)
# 说明
instruction_label = tk.Label(root, text="我已经想好了一个1-100的数字,你来猜!")
instruction_label.pack(pady=5)
# 输入框
entry_guess = tk.Entry(root, font=("Arial", 12))
entry_guess.pack(pady=10)
entry_guess.focus() # 让输入框自动获得焦点
# 按钮
button_guess = tk.Button(root, text="猜一下", command=check_guess, font=("Arial", 12))
button_guess.pack(pady=5)
button_restart = tk.Button(root, text="重新开始", command=restart_game, font=("Arial", 12))
button_restart.pack(pady=5)
# 结果标签
result_label = tk.Label(root, text="请输入1-100的数字", font=("Arial", 12))
result_label.pack(pady=10)
root.mainloop()
运行效果:
- 窗口标题:“猜数字游戏”
- 显示说明:“我已经想好了一个1-100的数字,你来猜!”
- 输入框:输入猜测的数字
- “猜一下“按钮:点击后检查猜测结果
- “重新开始“按钮:开始新游戏
- 结果标签:显示“太大了“、“太小了“或“恭喜你猜对了”
新知识点:
-
messagebox.showwarning("标题", "消息")- 显示警告对话框
- 有黄色的警告图标
-
messagebox.showerror("标题", "消息")- 显示错误对话框
- 有红色的错误图标
-
messagebox.showinfo("标题", "消息")- 显示信息对话框
- 有蓝色的信息图标
-
entry_guess.delete(0, tk.END)- 清空输入框的内容
0:从第0个字符开始tk.END:到末尾
-
entry_guess.focus()- 让输入框自动获得焦点
- 程序启动后可以直接输入,不需要先点击输入框
-
result_label.config(text="...", fg="red")- 修改标签的文字和颜色
fg是foreground(前景色)的缩写
16.5.2 更多改进思路
还可以继续改进这个游戏:
-
添加进度提示
# 显示还剩多少次机会 attempts_left_label = tk.Label(root, text=f"剩余机会:{max_attempts - attempts}") attempts_left_label.pack() -
添加历史记录
# 记录之前的猜测 history_label = tk.Label(root, text="历史记录:" + ", ".join(history)) history_label.pack() -
添加难度选择
# 简单:1-50,普通:1-100,困难:1-200
🎮 实践练习5:改写其他CLI程序
任务:选择一个之前写过的命令行程序,改写成GUI版本
建议选择:
- 计算器(第6章顺序语句)
- 成绩等级判断(第7章条件语句)
- 乘法口诀表(第8章循环语句)
- 简单计算器(第12章函数)
要求:
- 使用至少3种不同的组件
- 合理布局(美观、易用)
- 添加错误处理(输入非数字等)
- 添加说明文字
提示:
- 先画草图:界面怎么设计
- 列出需要的组件
- 选择合适的布局方式(pack或grid)
- 逐步添加功能,不要一次写完
16.6 美化界面
现在我们的程序功能已经完整,但界面还可以更漂亮!
16.6.1 设置字体和颜色
import tkinter as tk
root = tk.Tk()
root.title("美化界面")
root.geometry("400x300")
# 大标题
title_label = tk.Label(
root,
text="欢迎来到Python世界",
font=("Arial", 20, "bold"), # 字体、大小、加粗
fg="blue", # 前景色(文字颜色)
bg="yellow" # 背景色
)
title_label.pack(pady=20)
# 按钮
button = tk.Button(
root,
text="点击我",
font=("宋体", 14),
bg="green",
fg="white",
activebackground="darkgreen", # 点击时的背景色
activeforeground="white", # 点击时的文字颜色
relief="raised", # 边框样式:raised(凸起)、sunken(凹陷)、flat(扁平)
bd=3 # 边框宽度
)
button.pack(pady=10)
root.mainloop()
运行效果:
- 黄色背景、蓝色粗体大标题
- 绿色按钮(白色文字)
- 点击按钮时变成深绿色
16.6.2 常用颜色
tkinter支持多种颜色设置方式:
# 1. 颜色名称
fg="red"
fg="blue"
fg="green"
fg="yellow"
fg="black"
fg="white"
# 2. 十六进制颜色码(更精确)
fg="#FF0000" # 红色
fg="#0000FF" # 蓝色
fg="#00FF00" # 绿色
fg="#FFFF00" # 黄色
常用颜色速查表:
| 颜色 | 名称 | 十六进制 |
|---|---|---|
| 红色 | red | #FF0000 |
| 绿色 | green | #008000 |
| 蓝色 | blue | #0000FF |
| 黄色 | yellow | #FFFF00 |
| 黑色 | black | #000000 |
| 白色 | white | #FFFFFF |
| 橙色 | orange | #FFA500 |
| 紫色 | purple | #800080 |
16.6.3 设置组件大小
# 设置标签的大小(宽度和高度)
label = tk.Label(
root,
text="固定大小的标签",
width=20, # 宽度(字符数)
height=3 # 高度(行数)
)
# 设置按钮的大小
button = tk.Button(
root,
text="固定大小的按钮",
width=15,
height=2
)
🎨 实践练习6:美化猜数字游戏
任务:美化之前制作的猜数字游戏
要求:
- 标题使用大字体、加粗、蓝色
- 按钮使用绿色背景、白色文字
- 输入框使用大字体
- 结果文字根据情况显示不同颜色(太大=红色,太小=蓝色,正确=绿色)
- 添加背景色
🔍 查看答案
import random import tkinter as tk from tkinter import messagebox def check_guess(): user_input = entry_guess.get() if not user_input: messagebox.showwarning("提示", "请输入一个数字!") return try: guess = int(user_input) except ValueError: messagebox.showerror("错误", "请输入有效的数字!") return if guess < 1 or guess > 100: messagebox.showwarning("提示", "请输入1-100之间的数字!") return global attempts attempts += 1 if guess > secret: result_label.config(text="太大了!再试一次", fg="red") elif guess < secret: result_label.config(text="太小了!再试一次", fg="blue") else: result_label.config(text=f"恭喜你猜对了!答案就是{secret}!\n你用了{attempts}次。", fg="green") messagebox.showinfo("成功", f"恭喜你猜对了!\n答案:{secret}\n尝试次数:{attempts}") restart_game() def restart_game(): global secret, attempts secret = random.randint(1, 100) attempts = 0 result_label.config(text="游戏已重新开始!请猜1-100的数字", fg="black") entry_guess.delete(0, tk.END) # 初始化游戏 secret = random.randint(1, 100) attempts = 0 # 创建主窗口 root = tk.Tk() root.title("猜数字游戏") root.geometry("500x400") root.configure(bg="#f0f0f0") # 设置窗口背景色 # 标题 title_label = tk.Label( root, text="🎮 猜数字游戏(1-100)", font=("Arial", 20, "bold"), fg="blue", bg="#f0f0f0" ) title_label.pack(pady=15) # 说明 instruction_label = tk.Label( root, text="我已经想好了一个1-100的数字,你来猜!", font=("Arial", 12), bg="#f0f0f0" ) instruction_label.pack(pady=5) # 输入框 entry_guess = tk.Entry(root, font=("Arial", 14)) entry_guess.pack(pady=10) entry_guess.focus() # 按钮框架 button_frame = tk.Frame(root, bg="#f0f0f0") button_frame.pack(pady=10) button_guess = tk.Button( button_frame, text="🔍 猜一下", command=check_guess, font=("Arial", 12), bg="green", fg="white", width=10 ) button_guess.grid(row=0, column=0, padx=5) button_restart = tk.Button( button_frame, text="🔄 重新开始", command=restart_game, font=("Arial", 12), bg="orange", fg="white", width=10 ) button_restart.grid(row=0, column=1, padx=5) # 结果标签 result_label = tk.Label( root, text="请输入1-100的数字", font=("Arial", 14), bg="#f0f0f0" ) result_label.pack(pady=15) root.mainloop()
16.7 常见错误和调试
在编写GUI程序时,可能会遇到各种问题。让我们看看常见的错误和解决方法。
16.7.1 常见错误
错误1:窗口不显示
错误代码:
import tkinter as tk
root = tk.Tk()
# 忘记写 root.mainloop()
原因:忘记调用mainloop()
解决方法:在代码最后加上root.mainloop()
错误2:组件不显示
错误代码:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="你好")
# 忘记写 label.pack() 或 label.grid()
root.mainloop()
原因:创建组件后没有使用布局管理器(pack、grid或place)
解决方法:在创建组件后调用布局方法
label = tk.Label(root, text="你好")
label.pack() # 或 label.grid(...)
错误3:组件重叠
错误代码:
import tkinter as tk
root = tk.Tk()
# 同时使用pack和grid
label1 = tk.Label(root, text="标签1")
label1.pack()
label2 = tk.Label(root, text="标签2")
label2.grid(row=0, column=0)
root.mainloop()
错误提示:
_tkinter.TclError: cannot use geometry manager pack inside .!frame which already has slaves managed by grid
原因:在同一个父容器中混用pack和grid
解决方法:在同一个父容器中只使用一种布局方式
# 全部使用pack
label1.pack()
label2.pack()
# 或者全部使用grid
label1.grid(row=0, column=0)
label2.grid(row=1, column=0)
错误4:获取输入框内容时出错
错误代码:
def get_input():
# 用户没有输入任何内容
text = entry.get()
number = int(text) # 如果text是空字符串,会出错
错误提示:
ValueError: invalid literal for int() with base 10: ''
原因:输入框为空时,get()返回空字符串,无法转换为数字
解决方法:先检查是否为空
def get_input():
text = entry.get()
# 检查是否为空
if not text:
messagebox.showwarning("提示", "请输入内容!")
return
number = int(text)
错误5:函数调用时参数错误
错误代码:
def say_hello(name):
print(f"你好,{name}!")
button = tk.Button(root, text="点击", command=say_hello("小明"))
错误现象:程序启动时就调用了函数,而不是点击时调用
原因:command=say_hello("小明")会立刻执行函数,正确的做法是传递函数名
解决方法:使用lambda表达式
# 方法1:使用lambda
button = tk.Button(root, text="点击", command=lambda: say_hello("小明"))
# 方法2:改写函数,不使用参数
def say_hello():
name = entry.get()
print(f"你好,{name}!")
button = tk.Button(root, text="点击", command=say_hello)
16.7.2 调试技巧
技巧1:使用print调试
在关键位置添加print语句,查看程序执行情况
def check_guess():
guess = entry.get()
print(f"用户输入:{guess}") # 调试输出
if int(guess) > secret:
print("猜大了") # 调试输出
result_label.config(text="太大了")
技巧2:使用messagebox显示中间结果
def check_guess():
guess = entry.get()
messagebox.showinfo("调试", f"用户输入:{guess}")
# 后续代码...
技巧3:逐步添加功能
不要一次写完所有代码,而是逐步添加功能,每步都测试
# 第1步:先创建窗口
root = tk.Tk()
root.mainloop()
# 第2步:添加标签
root = tk.Tk()
label = tk.Label(root, text="你好")
label.pack()
root.mainloop()
# 第3步:添加按钮
root = tk.Tk()
label = tk.Label(root, text="你好")
label.pack()
button = tk.Button(root, text="点击")
button.pack()
root.mainloop()
# 第4步:添加功能
def on_click():
print("点击了")
button = tk.Button(root, text="点击", command=on_click)
技巧4:注释掉部分代码
如果程序出错,可以注释掉部分代码,逐步缩小问题范围
def complex_function():
# 注释掉复杂的部分
# result = some_calculation()
# another_function(result)
# 先测试简单部分
print("函数被调用")
🎮 实践练习7:调试练习
任务:找出下面代码中的5个错误并修正
import tkinter as tk def show_info(): name = entry.get() age = int(age_entry.get()) print(f"姓名:{name},年龄:{age}") root = tk.Tk() root.title("信息输入") label = tk.Label(root, text="姓名:") label.pack() entry = tk.Entry(root) entry.grid(row=0, column=1) # 错误1 age_label = tk.Label(root, text="年龄:") age_label.pack() age_entry = tk.Entry(root) age_entry.pack() button = tk.Button(root, text="提交", command=show_info()) # 错误2 button.pack() # 错误3:忘记mainloop()🔍 查看答案
错误1:混用pack和grid布局
# 错误 label.pack() entry.grid(row=0, column=1) # 正确:统一使用pack label.pack() entry.pack() # 或统一使用grid label.grid(row=0, column=0) entry.grid(row=0, column=1)错误2:command参数不应该加括号
# 错误 button = tk.Button(root, text="提交", command=show_info()) # 正确 button = tk.Button(root, text="提交", command=show_info)错误3:忘记mainloop()
# 正确 root.mainloop()额外问题:
- 如果age_entry为空,
int(age_entry.get())会报错- 应该添加错误处理
完整正确代码:
import tkinter as tk from tkinter import messagebox def show_info(): name = entry.get() age_text = age_entry.get() if not name or not age_text: messagebox.showwarning("提示", "请填写完整信息!") return try: age = int(age_text) result_label.config(text=f"姓名:{name},年龄:{age}") except ValueError: messagebox.showerror("错误", "年龄必须是数字!") root = tk.Tk() root.title("信息输入") root.geometry("300x200") label = tk.Label(root, text="姓名:") label.pack() entry = tk.Entry(root) entry.pack() age_label = tk.Label(root, text="年龄:") age_label.pack() age_entry = tk.Entry(root) age_entry.pack() button = tk.Button(root, text="提交", command=show_info) button.pack() result_label = tk.Label(root, text="") result_label.pack() root.mainloop()
16.8 本章小结
16.8.1 核心知识点回顾
1. GUI vs CLI
- GUI(图形用户界面):有窗口、按钮、颜色,用鼠标操作
- CLI(命令行界面):只有文字,用键盘输入命令
2. tkinter库
- Python自带的GUI库
- 可以创建窗口、按钮、输入框等组件
- 使用
root = tk.Tk()创建主窗口 - 使用
root.mainloop()让窗口持续显示
3. 常用组件
| 组件 | 类名 | 用途 |
|---|---|---|
| 标签 | Label | 显示文字或图片 |
| 按钮 | Button | 点击后执行操作 |
| 输入框 | Entry | 输入单行文字 |
| 文本框 | Text | 输入多行文字 |
| 复选框 | Checkbutton | 多选 |
| 单选按钮 | Radiobutton | 单选 |
4. 布局管理器
pack:按顺序排列(从上到下、从左到右)grid:网格排列(指定行和列)place:精确定位(指定坐标)
5. 事件处理
# 定义处理函数
def on_click():
print("按钮被点击")
# 绑定事件
button = tk.Button(root, text="点击", command=on_click)
6. messagebox对话框
messagebox.showinfo():显示信息messagebox.showwarning():显示警告messagebox.showerror():显示错误
7. 美化界面
font:设置字体fg:设置前景色(文字颜色)bg:设置背景色width、height:设置大小
16.8.2 能力检查表
学习完本章后,请检查自己是否掌握了以下技能:
- 能够创建一个tkinter窗口
- 能够在窗口中添加标签、按钮、输入框
- 能够使用pack和grid布局管理器
- 能够让按钮点击时执行某个函数
- 能够获取输入框的内容
- 能够使用messagebox显示对话框
- 能够设置组件的字体和颜色
- 能够将命令行程序改写为GUI版本
- 能够调试简单的GUI程序错误
16.8.3 常见问题快速参考
| 问题 | 解决方法 |
|---|---|
| 窗口不显示 | 检查是否调用了root.mainloop() |
| 组件不显示 | 检查是否调用了.pack()或.grid() |
| 点击按钮没反应 | 检查command=函数名是否正确(不要加括号) |
| 输入框获取内容出错 | 检查输入框是否为空,使用try-except处理错误 |
| 组件重叠 | 同一个父容器中不要混用pack和grid |
| 函数传参错误 | 使用lambda表达式:command=lambda: func(args) |
16.9 挑战练习
挑战1:计算器升级版 ⭐⭐
制作一个图形界面的计算器,要求:
- 有数字按钮(0-9)
- 有运算符按钮(+、-、×、÷)
- 有等号和清除按钮
- 有一个显示区域(Label)
提示:
- 使用grid布局排列按钮
- 点击数字按钮时,把数字添加到显示区域
- 点击等号时,计算表达式的结果(可以使用
eval()函数)
挑战2:记账本 ⭐⭐⭐
制作一个家庭记账本,要求:
- 可以输入收入或支出
- 可以输入金额、类别、备注
- 可以记录到列表中(用Label显示)
- 可以计算总收入、总支出、结余
- 可以清空所有记录
提示:
- 使用多个Entry输入不同信息
- 使用Radiobutton选择收入/支出
- 使用List或字典存储记录
- 使用Text组件显示所有记录
挑战3:待办事项清单 ⭐⭐⭐⭐
制作一个待办事项清单(TODO List),要求:
- 可以添加新的待办事项
- 可以标记事项为“已完成“
- 可以删除事项
- 可以按优先级排序(高/中/低)
- 可以保存到文件、从文件加载
提示:
- 使用Checkbutton标记完成状态
- 使用Radiobutton选择优先级
- 使用List或字典存储所有事项
- 使用文件操作保存和加载(第13章知识)
挑战4:单词卡片学习工具 ⭐⭐⭐⭐
制作一个英语单词学习工具,要求:
- 可以添加新单词(英文+中文)
- 可以随机显示单词
- 可以显示答案(中文意思)
- 可以标记为“已掌握“或“需要复习“
- 可以统计学习进度
提示:
- 使用字典存储单词:
{"apple": "苹果", "banana": "香蕉"} - 使用random模块随机选择单词
- 使用两个按钮:“显示答案“和“下一个单词”
挑战5:简单的绘图板 ⭐⭐⭐⭐⭐
制作一个简单的绘图板,要求:
- 可以选择颜色
- 可以选择画笔粗细
- 可以用鼠标在Canvas(画布)上画线
- 可以清除画布
- 可以保存画好的图片
提示:
- 使用Canvas组件(本章未介绍,需要查资料)
- 绑定鼠标事件:
<Button-1>(点击)、<B1-Motion>(拖动) - 使用
create_line()方法画线
16.10 下一步
恭喜你完成了第16章!你已经学会了:
✅ 创建图形界面程序 ✅ 使用常用组件(标签、按钮、输入框等) ✅ 管理界面布局 ✅ 处理用户操作(点击、输入等) ✅ 美化界面 ✅ 将命令行程序改写为GUI版本
你的技能树:
Python基础
├─ 变量和数据类型 ✅
├─ 条件语句 ✅
├─ 循环语句 ✅
├─ 函数 ✅
├─ 文件操作 ✅
├─ 命令行程序 ✅
├─ 数据可视化(pyecharts)✅
└─ 图形界面程序(tkinter)✅ ← 当前位置
下一章(第17章):程序设计
在最后一章中,你将学习:
- 如何评价一个程序的好坏
- 变量的设计原则
- 程序设计的一般方法
- 如何规划一个完整的程序
这将帮助你从“会写代码“提升到“会设计程序“!
附录:tkinter速查表
A1. 常用组件速查
# 导入tkinter
import tkinter as tk
from tkinter import messagebox
# 创建主窗口
root = tk.Tk()
root.title("窗口标题")
root.geometry("400x300")
# 标签
label = tk.Label(root, text="文字")
label.pack()
# 按钮
button = tk.Button(root, text="点击", command=函数名)
button.pack()
# 输入框
entry = tk.Entry(root)
entry.pack()
content = entry.get() # 获取内容
# 文本框(多行)
text = tk.Text(root, width=40, height=10)
text.pack()
content = text.get("1.0", "end") # 获取内容
# 复选框
var = tk.IntVar()
checkbutton = tk.Checkbutton(root, text="选项", variable=var)
checkbutton.pack()
if var.get() == 1: # 被选中
# 单选按钮
var = tk.StringVar()
var.set("选项1")
radio1 = tk.Radiobutton(root, text="选项1", variable=var, value="选项1")
radio2 = tk.Radiobutton(root, text="选项2", variable=var, value="选项2")
radio1.pack()
radio2.pack()
# 进入消息循环
root.mainloop()
A2. 布局管理器速查
# pack布局
component.pack() # 默认:从上到下
component.pack(side="left") # 从左到右
component.pack(side="right") # 从右到左
component.pack(padx=10, pady=10) # 外部间距
# grid布局
component.grid(row=0, column=0) # 第0行第0列
component.grid(row=1, column=2) # 第1行第2列
component.grid(columnspan=2) # 跨2列
component.grid(rowspan=3) # 跨3行
# place布局
component.place(x=100, y=50) # 精确定位
A3. 颜色速查
# 前景色(文字颜色)
fg="red"
fg="#FF0000"
# 背景色
bg="blue"
bg="#0000FF"
# 常用颜色
# red, blue, green, yellow, black, white, orange, purple
A4. messagebox速查
from tkinter import messagebox
# 信息对话框
messagebox.showinfo("标题", "消息内容")
# 警告对话框
messagebox.showwarning("标题", "消息内容")
# 错误对话框
messagebox.showerror("标题", "消息内容")
# 确认对话框(返回"yes"或"no")
result = messagebox.askyesno("标题", "确定吗?")
# 是/否/取消对话框(返回"yes"、"no"或"cancel")
result = messagebox.askyesnocancel("标题", "确定吗?")
学习建议:
- 多动手实践,每个例子都亲自运行一遍
- 尝试修改代码,看看效果有什么变化
- 把之前的CLI程序改写成GUI版本
- 设计自己的小工具(如记账本、学习计划表)
- 遇到问题时,先用print或messagebox调试
记住:学习编程最好的方法就是多写代码!💪