Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第16章 图形程序 - 让程序有“面子“

引言:从黑白世界到彩色世界

想象一下,如果你一直在用这样的方式和使用电脑程序:

请输入你的名字:小明
请输入你的年龄:12
你好,小明!你今年12岁了。

这是我们在前面章节中一直使用的命令行程序(Command Line Interface,简称CLI)。它的特点是:

  • 只能输入文字
  • 只能显示文字
  • 需要记住各种命令
  • 界面简陋(黑底白字)

但是现在,你用的QQ、微信、王者荣耀、我的世界……这些程序是什么样子的?

  • 有漂亮的窗口
  • 可以点击按钮
  • 可以在输入框里打字
  • 可以看到图片颜色
  • 可以用鼠标操作

这种程序叫图形界面程序(Graphical User Interface,简称GUI)!

什么是GUI?

GUI(Graphical User Interface)就是图形用户界面。让我们通过对比来理解:

特性命令行程序(CLI)图形界面程序(GUI)
外观黑底白字,只有文字彩色窗口,有图片、按钮、图标
操作方式只能用键盘输入命令可以用鼠标点击、拖拽
使用难度需要记住命令直观易懂,看图标就知道功能
例子我们之前的所有程序QQ、微信、游戏、浏览器

为什么学习GUI程序?

学习制作图形界面程序,你将能够:

  1. 制作真正“像样“的软件

    • 不再只是黑白的文字界面
    • 可以有漂亮的按钮、输入框、图片
    • 让你的程序看起来更专业
  2. 改善用户体验

    • 用户不需要记住命令
    • 看到按钮就知道能做什么
    • 操作更直观、更方便
  3. 将之前的程序“升级“

    • 把第14章的命令行课表查询程序改成带按钮的
    • 把计算器程序改成有按钮和显示屏幕的
    • 把猜数字游戏改成有界面的
  4. 理解日常软件的原理

    • 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?

  1. 免费且内置:Python安装时就自带了,不需要额外安装
  2. 简单易学:代码简洁,容易上手
  3. 功能够用:可以制作常见的界面元素
  4. 跨平台:在Windows、Mac、Linux上都能运行

tkinter能做什么?

  • ✅ 创建窗口
  • ✅ 添加按钮
  • ✅ 添加输入框
  • ✅ 添加文字标签
  • ✅ 添加图片
  • ✅ 添加下拉菜单
  • ✅ 添加复选框和单选按钮
  • ✅ 添加滑动条
  • ✅ ……还有很多其他组件

给家长的小贴士

  • GUI是现代软件的标准:几乎所有现代软件都使用图形界面
  • 培养用户思维:让孩子思考“怎么让用户更方便地使用程序“
  • 激发创造力:图形界面可以自由设计颜色、布局,孩子会很有成就感
  • 实际应用:可以制作家庭记账本、学习计划表等实用工具
  • 学习曲线:GUI比命令行程序复杂一些,需要更多耐心
  • 建议:先让孩子熟悉一个简单例子,再鼓励他设计自己的界面

16.1 第一个窗口程序

16.1.1 最简单的窗口

让我们从最简单的开始——创建一个空白窗口!

# 导入tkinter库
import tkinter as tk

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

# 进入消息循环(让窗口一直显示)
root.mainloop()

运行结果: 弹出一个空白窗口!

代码解释:

  1. import tkinter as tk

    • 导入tkinter库
    • as tk表示给tkinter起个简短的别名,以后用tk代替tkinter
  2. root = tk.Tk()

    • 创建一个主窗口
    • Tk()是创建主窗口的函数
    • root是这个窗口的名字(你可以叫它windowmain_window
  3. 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),完成以下组件的放置:

  1. 标签“标题“:放在窗口正上方(x=200, y=20,宽200,高30)
  2. 按钮“确定“:放在窗口正中央,大小100×40
  3. 按钮“取消“:放在“确定“按钮右边50像素处
  4. 计算“确定“按钮的坐标(x, y)
  5. 计算两个按钮总共占多少面积

答案:

🔍 查看答案
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()

运行结果: 窗口中显示了一行文字:“你好,这是我的第一个标签!”

代码解释:

  1. tk.Label(root, text="...")

    • root:表示这个标签要放在哪个窗口里
    • text="...":标签上显示的文字
  2. 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()

运行结果: 每次点击按钮,在命令行(终端/黑窗口)中会输出:“按钮被点击了!”

代码解释:

  1. def on_button_click():

    • 定义了一个函数
    • 这个函数包含了点击按钮时要执行的代码
  2. command=on_button_click

    • command是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()

运行结果:

  1. 在输入框输入名字,比如“小明“
  2. 点击“问候“按钮
  3. 下面会显示:“你好,小明!”

代码解释:

  1. entry.get()

    • 获取输入框中用户输入的内容
    • 返回一个字符串
  2. 每次点击按钮,都会创建一个新标签显示问候语

🎮 实践练习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提供了三种布局管理器:

  1. pack:按顺序排列(简单)
  2. grid:网格排列(灵活)
  3. 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()

运行结果:

用户名: [输入框]
密码:   [输入框]
[     登录按钮     ]

代码解释:

  1. row=0, column=0:放在第0行、第0列(注意:从0开始计数!)
  2. 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. 窗口标题:“猜数字游戏”
  2. 显示说明:“我已经想好了一个1-100的数字,你来猜!”
  3. 输入框:输入猜测的数字
  4. “猜一下“按钮:点击后检查猜测结果
  5. “重新开始“按钮:开始新游戏
  6. 结果标签:显示“太大了“、“太小了“或“恭喜你猜对了”

新知识点:

  1. messagebox.showwarning("标题", "消息")

    • 显示警告对话框
    • 有黄色的警告图标
  2. messagebox.showerror("标题", "消息")

    • 显示错误对话框
    • 有红色的错误图标
  3. messagebox.showinfo("标题", "消息")

    • 显示信息对话框
    • 有蓝色的信息图标
  4. entry_guess.delete(0, tk.END)

    • 清空输入框的内容
    • 0:从第0个字符开始
    • tk.END:到末尾
  5. entry_guess.focus()

    • 让输入框自动获得焦点
    • 程序启动后可以直接输入,不需要先点击输入框
  6. result_label.config(text="...", fg="red")

    • 修改标签的文字和颜色
    • fg是foreground(前景色)的缩写

16.5.2 更多改进思路

还可以继续改进这个游戏:

  1. 添加进度提示

    # 显示还剩多少次机会
    attempts_left_label = tk.Label(root, text=f"剩余机会:{max_attempts - attempts}")
    attempts_left_label.pack()
    
  2. 添加历史记录

    # 记录之前的猜测
    history_label = tk.Label(root, text="历史记录:" + ", ".join(history))
    history_label.pack()
    
  3. 添加难度选择

    # 简单: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:设置背景色
  • widthheight:设置大小

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("标题", "确定吗?")

学习建议

  1. 多动手实践,每个例子都亲自运行一遍
  2. 尝试修改代码,看看效果有什么变化
  3. 把之前的CLI程序改写成GUI版本
  4. 设计自己的小工具(如记账本、学习计划表)
  5. 遇到问题时,先用print或messagebox调试

记住:学习编程最好的方法就是多写代码!💪