本书红线(贯穿全教程,回顾):
1. 每个界面都用class App:封装,__init__里建控件,方法即事件回调。
2. 所有控件示例一律写在类里,不用脱离类的扁平脚本。
3. 代码块带if __name__ == "__main__":守卫,可独立运行。
4. 星级:★ 了解 · ★★ 理解 · ★★★ 掌握 · ★★★★ 重点必会。
主线项目:图形界面通讯录管理器,随章节每章新增一个控件慢慢长大。
上节回顾(第 5 章):你学会了 Entry 单行输入,并用 StringVar 把"输入框"和"变量"双向绑定,让程序能读出用户打的字(比如姓名)。但 Entry 只能装"一行",装不下一大段话。
本章目标:认识多行输入控件——Text。它能装下好几段文字,适合做"备注""日志""大文本框"。我们会学怎么取出全部文字、怎么追加、怎么清空,以及用 tag 给一段文字上色(先认识概念)。最后把它和第 5 章的 Entry 做个对比。
是什么:Text 是一个多行文本区域,可以输入、显示、编辑大段文字,支持滚动、不同字体、甚至图文混排(进阶)。它比 Entry 强大得多。
适用场景:
不适用:只填一个值(姓名、电话)用 Entry 就够了;Text 太重。
下面是 Text 最常用的选项(来自官方 tkinter.Text 文档):
| 选项 | 作用 | 常用取值 | 重要度 |
|---|---|---|---|
height | 可见行数(行,非像素) | 整数,如 10 | ★★★★ |
width | 可见列数(字符数) | 整数,如 40 | ★★★★ |
font | 字体字号 | 元组 ("微软雅黑", 12) | ★★★ |
fg / bg | 文字色 / 背景色 | 颜色字符串 | ★★★ |
wrap | 文字到边界是否换行 | "word"(按词换行,默认)/"char"(按字符)/"none"(不换行) | ★★★ |
state | 是否可编辑 | "normal"(可编辑,默认)/"disabled"(只读) | ★★★ |
relief / borderwidth | 边框样式 / 粗细 | "sunken"(默认凹陷) 等 | ★★ |
padx / pady | 文字到边框的内边距(像素) | 整数 | ★★ |
📌wrap="word"的意义:长行默认按"单词"折行,不会出现把中文词从中间切断的尴尬(配合宽度使用)。想让中文也优雅换行,通常用默认的wrap="word"即可。
Text 的方法很多,先掌握这几个核心(注意它的"位置"用 "行.列" 表示,如 "1.0" 指第 1 行开头):
| 方法 | 作用 | 示例 |
|---|---|---|
get(起始, 结束) | 取出一段文字 | self.text.get("1.0", tk.END) 取全部 |
insert(位置, 文字) | 在指定位置插入文字 | self.text.insert(tk.END, "新行\n") 末尾追加 |
delete(起始, 结束) | 删除一段文字 | self.text.delete("1.0", tk.END) 清空全部 |
insert(tk.INSERT, 文字) | 在"当前光标处"插入 | self.text.insert(tk.INSERT, "字") |
tag_add(标签, 起, 止) | 给一段文字打上标签(用于上色) | self.text.tag_add("hl", "1.0", "1.5") |
tag_config(标签, 选项) | 配置某标签的样式(颜色等) | self.text.tag_config("hl", foreground="red") |
行号格式"行.列":Text 里每个字符都有坐标,格式是"行.列"。行从1开始,列从0开始。所以"1.0"= 第 1 行最开头;"2.3"= 第 2 行第 4 个字符前。tk.END是末尾,tk.INSERT是当前光标位置。
本章用tk.Text。所有示例写在class App:里,并沿用_build_widgets的拆分习惯。
# 第6章 例6.1:一个多行文本框 + 按钮,点按钮读出全部文字
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
self._build_widgets()
def _build_widgets(self):
tk.Label(self.root, text="联系人备注:").pack(pady=5)
# 多行文本框:高 10 行、宽 40 字符
self.text = tk.Text(self.root, height=10, width=40, wrap="word")
self.text.pack(padx=5, pady=5)
tk.Button(self.root, text="读取备注", command=self.on_read).pack(pady=5)
def on_read(self):
# get("1.0", tk.END):从第 1 行开头取到末尾 = 全部内容
content = self.text.get("1.0", tk.END)
print("备注内容是:\n", content)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
self.text = tk.Text(self.root, height=10, width=40, wrap="word"):创建多行框,可见 10 行高、40 字符宽,长行按词换行。content = self.text.get("1.0", tk.END):取全部文字。"1.0" 是第 1 行开头,tk.END 是末尾。返回的是一个字符串(末尾通常带一个换行符 \n,属正常)。模拟一个"日志框":点"追加"在末尾加一行;点"清空"用 delete("1.0", tk.END) 清掉。
# 第6章 例6.2:日志风格——追加一行、清空全部
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
self._build_widgets()
def _build_widgets(self):
self.log = tk.Text(self.root, height=8, width=40, state="normal")
self.log.pack(padx=5, pady=5)
tk.Button(self.root, text="追加一行", command=self.on_append).pack(pady=2)
tk.Button(self.root, text="清空日志", command=self.on_clear).pack(pady=2)
def on_append(self):
# 在末尾追加一行文字(\n 表示换行,否则接在上次末尾)
self.log.insert(tk.END, "有新联系人加入\n")
def on_clear(self):
# 清空:从第 1 行开头删到末尾
self.log.delete("1.0", tk.END)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
self.log.insert(tk.END, "有新联系人加入\n"):tk.END 是"当前末尾",所以每次都在最后追加。\n 让每次追加都另起一行,否则文字会连在一起。self.log.delete("1.0", tk.END):清空全部内容。注意它和 Entry 的 delete(0, tk.END) 很像,只是 Text 的起始位置写成字符串 "1.0" 而不是数字 0。tk.INSERT 表示"当前光标位置";tag 可以给一段文字单独上色。下面演示:点按钮在光标处插入文字,并把刚插入的文字标红。
# 第6章 例6.3:在光标处插入文字,并用 tag 给该段文字上红色(概念入门)
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
self.root.title("通讯录管理器")
self._build_widgets()
def _build_widgets(self):
self.text = tk.Text(self.root, height=8, width=40)
self.text.pack(padx=5, pady=5)
# 先定义一个名为 "hl" 的标签样式:前景(文字)红色、加粗
self.text.tag_config("hl", foreground="red", font=("微软雅黑", 12, "bold"))
tk.Button(self.root, text="插入高亮文字", command=self.on_insert).pack(pady=5)
def on_insert(self):
# 在光标处插入一段文字
self.text.insert(tk.INSERT, "重要提醒!")
# 给"刚刚插入的这一段"打上 hl 标签,使其变红加粗
# 这里简单演示:对当前光标前 5 个字符上色("重要提醒!"正好 5 字)
end = self.text.index(tk.INSERT) # 当前光标位置(字符串如 "1.5")
start = f"{end.split('.')[0]}.{int(end.split('.')[1]) - 5}"
self.text.tag_add("hl", start, end)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()逐行说明:
self.text.tag_config("hl", foreground="red", ...):先"定义"一个叫 hl 的样式标签——文字红色、加粗。定义一次,之后凡是被打上 hl 标签的文字都套用这个样式。self.text.insert(tk.INSERT, "重要提醒!"):tk.INSERT 是"当前光标位置",文字插在光标处。self.text.tag_add("hl", start, end):把从 start 到 end 这一段文字标记为 hl,于是它显示成红色加粗。tag_add + tag_config 配合,就能给任意一段文字单独上色——这是 Text 比 Entry 强大之处(本章先认识概念,后续章节会深入)。self 上的一个对象:和 Label、Button、Entry 一样,多行框存成 self.text,整个类随时读写它。get/insert/delete 操作的一块文本区域。tag 是"样式对象"的雏形:tag_config 把"某种样式"定义好、tag_add 把它应用到文字区间——这其实就是"样式与内容分离"的思想雏形,会和第 7 章的 ttk.Style 呼应。一句话:Entry 装一行、Text 装一整片;两者都是"界面上的可编辑区域",但 Text 能分段、能上色、能做日志。
"1.0" 而非数字:get("1.0", tk.END) 里 "1.0" 是字符串。若误写成 get(1.0, tk.END),Python 会把 1.0 当成浮点数 1.0,会报类型错误。记住 Text 坐标永远是 "行.列" 字符串。delete("1.0", tk.END),不是 entry.delete(0, tk.END)(那是 Entry 的)。两者起始位置写法不同。get 末尾会多一个换行符 \n:get("1.0", tk.END) 取到的字符串末尾常带一个 \n(Text 总是在末尾维护一个换行)。比较/处理内容时注意 strip()。state="disabled",但此时 insert 也写不进去了。常见做法是:插入时临时 state="normal",插入完再 state="disabled"。tag 必须先 tag_config 再 tag_add:没定义样式就 tag_add,文字不会有颜色变化(标签存在但无样式)。get,想设置就 delete+insert。get("1.0", tk.END) 读出内容并打印(提示:用 len() 计字符数,记得 strip() 去掉末尾换行)。delete("1.0", tk.END) 清空;再加一个"加载示例"按钮,用 insert(tk.END, "示例备注文字") 填入一段文字。tag 给 Text 里的某一行文字上蓝色(参考例 6.3,先 tag_config 定义样式,再 tag_add 应用到指定行区间)。textvariable=StringVar() 绑定?(提示:StringVar 只能保存单行字符串,而 Text 是一整片可分段、可带样式的多行内容,数据模型不匹配,所以 tkinter 只提供 get/insert/delete 这类方法直接操作。)下节预告:第 7 章我们让界面"换皮肤"——认识ttk主题控件模块和Style样式对象,把土味原生界面升级成现代风格,并学会统一换肤。