本书红线(贯穿全教程,回顾):
1. 每个界面都用class App:封装,__init__里建控件,方法即事件回调。
2. 所有控件示例一律写在类里,不用脱离类的扁平脚本。
3. 代码块带if __name__ == "__main__":守卫,可独立运行。
4. 星级:★ 了解 · ★★ 理解 · ★★★ 掌握 · ★★★★ 重点必会。
主线项目:图形界面通讯录管理器,随章节每章新增一个控件慢慢长大。
上节回顾(第 4 章):你学会了 pack / grid / place 三种布局管理器,能把 Label、Button 排整齐、排成表格,还建立了"用 _build_widgets 把建界面和事件逻辑分离"的 OOP 习惯。不过界面还只能"显示"和"点击",没有地方让用户输入文字。
本章目标:引入第一个能输入的控件——Entry(单行输入框),让用户输入一行文字(比如姓名),程序能读出来。重点是学会变量绑定:用 tk.StringVar() 把"输入框"和"一个变量"双向关联,之后读写都用这个变量,比直接操作 Entry 更 OOP、更清爽。本章还顺带认识 show="*" 做密码框。
是什么:Entry 是一个单行文本框,用户可以在里面打字,程序可以读取或设置里面的文字。它和 Label 相反——Label 只能"看",Entry 可以"写(输入)"。
适用场景:
不适用:要输入一大段文字(如备注、日志),请等第 6 章的 Text 多行控件。
下面是 Entry 最常用的选项(来自官方 tkinter.Entry 文档):
| 选项 | 作用 | 常用取值 | 重要度 |
|---|---|---|---|
textvariable | 绑定一个 StringVar,变量变文字跟着变 | self.name_var(一个 tk.StringVar()) | ★★★★ |
show | 把输入的字符替换成指定符号(做密码框) | "*" 或 "●" | ★★★ |
width | 输入框可见宽度(字符数,非像素) | 整数,如 20 | ★★★ |
font | 字体字号 | 元组 ("微软雅黑", 12) | ★★ |
fg / bg | 文字色 / 背景色 | 颜色字符串 | ★★ |
state | 是否可编辑 | "normal"(可编辑,默认)/"readonly"(只读)/"disabled"(禁用) | ★★★ |
justify | 输入文字在框内的对齐 | "left"(默认)/"center"/"right" | ★★ |
relief / borderwidth | 边框样式 / 粗细 | "sunken"(默认凹陷) 等 | ★ |
📌textvariable是本章核心:有了它,就不用每次都去entry.get()拿文字,而是直接读绑定的StringVar。详见 5.4 节。
| 方法 | 作用 | 示例 |
|---|---|---|
get() | 读取输入框当前文字(返回字符串) | text = self.entry.get() |
insert(索引, 文字) | 在指定位置插入文字 | self.entry.insert(0, "默认值") |
delete(起始, 结束) | 删除一段文字(含起始不含结束) | self.entry.delete(0, tk.END) 清空全部 |
config(state=...) | 运行时改状态(只读/禁用) | self.entry.config(state="readonly") |
索引规则:Entry 里文字的"位置"从左到右用数字编号,最左边是0。tk.END表示"末尾"。所以delete(0, tk.END)就是"从第 0 个字符删到末尾"= 清空。
本章引入 tk.Entry。重点示例都演示 StringVar 绑定,这才是更 OOP 的写法。
先不绑定变量,用 entry.get() 直接读,建立"输入框能读出字"的直觉:
# 第5章 例5.1:一个输入框 + 一个按钮,点按钮把输入的名字打印出来
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
# 提示文字
self.tip = tk.Label(self.root, text="请输入姓名:")
self.tip.pack(pady=5)
# 单行输入框:width=20 表示可见 20 个字符宽
self.entry = tk.Entry(self.root, width=20)
self.entry.pack(pady=5)
# 按钮:点它调用 on_submit
self.btn = tk.Button(self.root, text="确定", command=self.on_submit)
self.btn.pack(pady=5)
def on_submit(self):
# 读取输入框当前文字,存进变量 name
name = self.entry.get()
print("你输入的姓名是:", name)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
self.entry = tk.Entry(self.root, width=20):创建单行输入框,可见宽度 20 字符。它存进 self.entry,方法里随时可用。name = self.entry.get():在按钮回调里读取用户输入。get() 返回字符串。运行后输入"张三"点确定,控制台打印"你输入的姓名是: 张三"。StringVar 是 tkinter 的"字符串变量"类型。把它绑到 Entry 的 textvariable 上后,输入框内容和这个变量就同步了:用户在框里打字,变量自动更新;程序用 变量.set("xx") 改值,框里也跟着变。
# 第5章 例5.2:用 StringVar 把输入框和变量绑定,读写都通过变量(更 OOP)
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
# ① 先创建一个 StringVar,作为"姓名"的数据来源
self.name_var = tk.StringVar()
self.tip = tk.Label(self.root, text="请输入姓名:")
self.tip.pack(pady=5)
# ② 输入框的 textvariable 指向 self.name_var,二者绑定
self.entry = tk.Entry(self.root, textvariable=self.name_var, width=20)
self.entry.pack(pady=5)
self.btn = tk.Button(self.root, text="确定", command=self.on_submit)
self.btn.pack(pady=5)
def on_submit(self):
# ③ 读取时不再调 entry.get(),而是读绑定的变量
name = self.name_var.get()
print("姓名变量里的值是:", name)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
self.name_var = tk.StringVar():创建一个 tkinter 字符串变量。注意它不是普通 Python 变量,必须用 get()/set() 访问。textvariable=self.name_var:把输入框和这个变量绑定。从此"框里显示什么"和"变量里存什么"是一回事。name = self.name_var.get():读值用变量的 get()。用户打字 → 变量自动更新 → 点按钮读到最新值。self.name_var.set("李四"),输入框里会立刻显示"李四"。这就是"双向联动"。把例 5.2 升级:点"确定"把姓名显示到一个结果 Label;点"清空"按钮用 delete(0, tk.END) 清掉输入。
# 第5章 例5.3:点"确定"把输入显示到 Label,点"清空"用 delete 清掉输入框
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
self.name_var = tk.StringVar()
self.tip = tk.Label(self.root, text="请输入姓名:")
self.tip.pack(pady=5)
self.entry = tk.Entry(self.root, textvariable=self.name_var, width=20)
self.entry.pack(pady=5)
# 显示结果的 Label,初始提示
self.result = tk.Label(self.root, text="(结果将显示在这里)", fg="blue")
self.result.pack(pady=5)
self.ok_btn = tk.Button(self.root, text="确定", command=self.on_ok)
self.ok_btn.pack(pady=2)
self.clear_btn = tk.Button(self.root, text="清空", command=self.on_clear)
self.clear_btn.pack(pady=2)
def on_ok(self):
# 读变量,把姓名显示到结果 Label
name = self.name_var.get()
self.result.config(text=f"你好,{name}!")
def on_clear(self):
# 清空输入框:从 0 删到末尾
self.entry.delete(0, tk.END)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
self.result.config(text=f"你好,{name}!"):点确定后把读到的姓名显示到结果 Label(复习第 3 章"方法即回调 + config 改界面")。self.entry.delete(0, tk.END):清空输入框全部内容。tk.END 是 tkinter 常量,代表"末尾"。这是清空 Entry 的正确方式。show="*" 让输入显示为星号,适合密码;insert(0, "默认") 可预设初始文字。
# 第5章 例5.4:密码框(show="*")与预设默认值(insert)
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
self.pw_var = tk.StringVar()
tk.Label(self.root, text="密码:").pack(pady=5)
self.pw_entry = tk.Entry(
self.root, textvariable=self.pw_var, show="*", width=20 # show="*" 输入显示为星号
)
self.pw_entry.pack(pady=5)
# 预设一个默认值(在位置 0 插入文字)
self.pw_entry.insert(0, "123456")
self.btn = tk.Button(self.root, text="显示真实密码", command=self.show_pw)
self.btn.pack(pady=5)
def show_pw(self):
# 虽然界面显示星号,但变量里仍是真实字符
print("真实密码是:", self.pw_var.get())
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
show="":用户输入的字符全部显示为 ,起到遮挡作用(注意:这只是显示遮挡,真实内容存在变量里,例 5.4 的 show_pw 仍能打印真实值)。self.pw_entry.insert(0, "123456"):在位置 0(最左)插入默认文字"123456"。运行后框里预先就有"123456"(显示为星号)。tk.Entry(...) 返回输入框对象,tk.StringVar() 返回变量对象。两者通过 textvariable 绑定,构成"界面控件 ↔ 数据"的桥梁。self 持有输入状态:把 self.name_var = tk.StringVar() 存成实例属性,整个 App 对象都能读写用户输入。这正是 GUI 程序的典型模式——用户输入被收进对象的属性,事件方法从属性里取数据。entry.get() 更 OOP:绑定变量后,业务逻辑只和 self.name_var 打交道,不直接依赖界面控件。将来换控件、加校验,只要变量不动,逻辑就不受影响——这就是"数据"与"视图"解耦的雏形。一句话:Entry 管"用户打字",StringVar 管"程序读写的那个值",两者绑定后各司其职。
delete(0, tk.END),而不是 set(""):StringVar.set("") 只能清掉"变量",但若 Entry 没用 textvariable 绑定(或想直接清框),必须用 entry.delete(0, tk.END)。对已绑定的 Entry,清框也推荐用 delete,因为 set("") 只改了变量、有时和渲染不同步。__init__ 里就 entry.get() 想拿用户输入——那时用户还没打字,拿到的是空字符串。正确时机是"点按钮(回调)时"才取。StringVar 不是普通字符串:对它用普通字符串操作(如 self.name_var + "x")会报错。读写必须用 self.name_var.get() / self.name_var.set(...)。textvariable 绑定就用变量读:若只 tk.Entry(self.root) 没绑 textvariable,那 self.name_var.get() 永远取到空。要么绑定后用变量,要么老老实实用 entry.get()。show 的坑:部分平台/输入法在中文输入过程中,show="*" 可能短暂显示拼音或原字符;这是底层输入法行为,属正常现象,提交后内容以变量里为准。state="readonly" 与 disabled 区别:readonly 仍可复制、靠代码 set 改;disabled 完全冻结。想"能看不能改"用 readonly。delete(0, tk.END) 清掉输入框;结果同时显示到一个 Label 上。show="*")、"登录"按钮;点登录时把两者用 StringVar 读出并打印。self.name_var.set("") 而不是 self.entry.delete(0, tk.END),会有什么不同?(提示:两者在已绑定的情况下效果通常一致,但若 Entry 有独立状态或想确保框内视觉清空,用 delete 最直接;理解"变量"与"控件显示"是两个层面。)下节预告:第 6 章我们认识多行输入控件——Text,用来输入/显示一大段文字(如备注、日志),并学习get/insert/delete和用tag给文字上色。