📚 目录 第 9 章 下拉与调节:Combobox / Scale / Spinbox(更省空间的选择与调数)

第 9 章 下拉与调节:Combobox / Scale / Spinbox(更省空间的选择与调数)

本书红线(贯穿全教程,回顾):
1. 每个界面都用 class App: 封装,__init__ 里建控件,方法即事件回调。
2. 所有控件示例一律写在类里,不用脱离类的扁平脚本。
3. 代码块带 if __name__ == "__main__": 守卫,可独立运行。
4. 星级:★ 了解 · ★★ 理解 · ★★★ 掌握 · ★★★★ 重点必会。

主线项目:图形界面通讯录管理器,随章节每章新增一个控件慢慢长大。

上节回顾(第 8 章):你学会了用 Checkbutton 做"勾选/多选"(绑 BooleanVar,True/False),用 Radiobutton 做"单选"(一组共用一个 variable,各钮 value 不同)。本章给通讯录加上更省空间的"选择/调数"控件——Combobox(下拉框)、Scale(滑块)、Spinbox(数字微调框)。

本章目标:认识三个"省空间"控件——Combobox(下拉选一个值)、Scale(拖动滑块选连续数值)、Spinbox(点上下箭头调数字)。重点是 from_ 带下划线的坑、Combobox 用 state="readonly" 防止手输、get()/set() 取值设值。OOP 落点:把它们都收进 self,用方法读取用户的选择回填到 Label 或数据。


9.1 是什么 / 适用场景 ★

控件是什么通讯录用法
ttk.Combobox下拉框:平时只显示当前选中的一项,点开才列出全部选项选"分类:同事/家人/客户"
ttk.Scale滑块:拖动小圆点在一个范围内连续取值选"年龄:0–120"
ttk.Spinbox数字微调框:一个框 + 上下箭头,点箭头在范围内 +1/-1选"第几组 / 年龄精确数"

对比第 8 章:选项少(2–3 个)且想一眼看到全部 → 用 Radiobutton;选项多(5 个以上)或想省地方 → 用 Combobox;值是连续数字(如年龄、音量)→ Scale;值是整数步进 → Spinbox。


9.2 构造选项(对照官方手册)★★

下面选项来自官方 tkinter.ttk 文档(Combobox / Scale / Spinbox):

控件选项作用常用取值重要度
Comboboxvalues下拉里的可选项(元组/列表)("同事","家人","客户")★★★★
Comboboxstate是否可手输"readonly"(禁手输,只能选) / "normal"★★★
Comboboxtextvariable绑定变量读取值tk.StringVar()★★★
Scalefrom_最小值(注意下划线!)0★★★★
Scaleto最大值120★★★★
Scaleorient方向"horizontal" / "vertical"★★
Scalevariable绑定变量tk.DoubleVar() / tk.IntVar()★★★
Spinboxfrom_最小值(注意下划线)0★★★★
Spinboxto最大值100★★★★
Spinboxincrement每点一次的步长1★★★
Spinboxtextvariable绑定变量tk.IntVar()★★★
三者通用command值变化时回调self.on_change★★★
📌 全章最致命的坑:Scale/Spinbox 的最小值是 from_(带下划线),不是 from。from 是 Python 关键字,直接写会语法报错。给 Combobox 设 state="readonly" 能避免用户乱输脏数据。

9.3 常用方法速查 ★★

控件方法作用示例
Comboboxget()取当前选中的文字cb.get()
Comboboxset(值)设置显示的文字(必须存在于 values)cb.set("家人")
Comboboxcurrent(索引)按位置选中第几项(0 起)cb.current(0)
Scaleget()取当前数值scale.get()
Scaleset(值)设置滑块位置scale.set(30)
Spinboxget()取当前数字(字符串)sb.get()
Spinboxget() + int()取整数int(sb.get())
三个控件都能用 textvariable/variable 绑定变量,然后 var.get() 读、var.set() 写——和第 8 章的变量思路一致。也可直接用控件自带的 get()/set(),效果等价。

9.4 详细例子(循序渐进)★★★

每个例子都写在 class App 里,可直接运行(本机会弹出窗口)。

例 9.1 Combobox 选"分类"(readonly 防手输)★★★

通讯录里给联系人选"同事/家人/客户",用下拉框最省空间。

# 第9章 例9.1:用 Combobox 选择联系人"分类"
import tkinter as tk
from tkinter import ttk


class App:
    def __init__(self, root):
        self.root = root
        self.root.title("通讯录管理器 - 选择分类")

        # ① 创建 Combobox:values 是下拉里的选项;state="readonly" 禁止用户手输
        self.cat_cb = ttk.Combobox(
            self.root,
            values=("同事", "家人", "客户"),  # 下拉可选项
            state="readonly",                  # 只能从列表选,不能乱打字
        )
        self.cat_cb.current(0)               # ② 默认选中第 0 项("同事")
        self.cat_cb.pack(padx=20, pady=10)

        # ③ 确认按钮:点击后把选中项显示在 Label
        self.btn = ttk.Button(self.root, text="确认分类", command=self.confirm)
        self.btn.pack(padx=20, pady=10)

        self.label = ttk.Label(self.root, text="(请选择分类)")
        self.label.pack(padx=20, pady=10)

    def confirm(self):
        # ④ get() 直接拿到下拉当前选中的文字
        self.label.config(text=f"分类:{self.cat_cb.get()}")


if __name__ == "__main__":
    root = tk.Tk()
    App(root)
    root.mainloop()

逐行说明:

例 9.2 Scale 滑块选年龄(from_ 带下划线)★★★

年龄是连续数值,用滑块最直观。

# 第9章 例9.2:用 Scale 滑块选择"年龄"
import tkinter as tk
from tkinter import ttk


class App:
    def __init__(self, root):
        self.root = root
        self.root.title("通讯录管理器 - 年龄")

        # ① 滑块:from_ 是最小值(注意下划线!),to 是最大值,horizontal 水平摆放
        self.age_scale = ttk.Scale(
            self.root,
            from_=0,                  # 最小值 0(务必写成 from_,不是 from)
            to=120,                  # 最大值 120
            orient="horizontal",     # 水平滑块
            command=self.on_scale,   # 拖动时持续触发
        )
        self.age_scale.set(20)       # ② 初始值设为 20
        self.age_scale.pack(padx=20, pady=10, fill="x")

        self.label = ttk.Label(self.root, text="年龄:20")
        self.label.pack(padx=20, pady=10)

    def on_scale(self, value):
        # ③ value 是字符串,转成 int 显示;拖动时实时更新
        age = int(float(value))
        self.label.config(text=f"年龄:{age}")


if __name__ == "__main__":
    root = tk.Tk()
    App(root)
    root.mainloop()

逐行说明:

例 9.3 Spinbox 数字微调 + 与 Combobox 组合 ★★★

Spinbox 点上下箭头在范围内调整数;和 Combobox 一起做更完整的表单。

# 第9章 例9.3:用 Spinbox 调"亲密指数",与 Combobox 组合显示
import tkinter as tk
from tkinter import ttk


class App:
    def __init__(self, root):
        self.root = root
        self.root.title("通讯录管理器 - 添加")

        # ① Combobox 选分类(只读)
        self.cat_cb = ttk.Combobox(
            self.root, values=("同事", "家人", "客户"), state="readonly",
        )
        self.cat_cb.current(0)
        self.cat_cb.pack(padx=20, pady=5)

        # ② Spinbox:from_=1, to=10, increment=1,点箭头在 1~10 间步进
        self.score_sb = ttk.Spinbox(
            self.root,
            from_=1,                 # 最小值 1(下划线!)
            to=10,                  # 最大值 10
            increment=1,            # 每点一次 ±1
            wrap=True,              # 到边界后绕回另一头(可选)
        )
        self.score_sb.set(5)        # ③ 初值 5
        self.score_sb.pack(padx=20, pady=5)

        self.btn = ttk.Button(self.root, text="保存", command=self.save)
        self.btn.pack(padx=20, pady=10)

        self.label = ttk.Label(self.root, text="(等待保存)")
        self.label.pack(padx=20, pady=10)

    def save(self):
        cat = self.cat_cb.get()                  # ④ 读下拉文字
        score = int(self.score_sb.get())        # ⑤ 读微调框数字(转 int)
        self.label.config(text=f"分类:{cat} 亲密指数:{score}")


if __name__ == "__main__":
    root = tk.Tk()
    App(root)
    root.mainloop()

逐行说明:


9.5 OOP 落点 ★★


9.6 注意事项 / 易错清单 ★★


9.7 本章练习

  1. 写一个程序:用 Combobox 选"城市"(values=("北京","上海","广州","深圳")),点按钮把所选城市显示在 Label(提示:state="readonly" + current(0))。
  2. 写一个程序:用 Scale 选"音量 0–100",拖动时 Label 实时显示"音量:XX";用 orient="vertical" 试一次垂直滑块。
  3. 综合练习:用 Combobox 选"分类"(同事/家人/客户),用 Scale 选"年龄(0–120)",点按钮把两项显示在 Label。
  4. 思考题:例 9.2 如果把 from_=0 误写成 from=0,会发生什么?(提示:Python 把 from 当成关键字,from=0 是语法错误,_validate.py 会报 invalid syntax,程序根本跑不起来。)
下节预告:第 10 章我们学 Listbox——一次性显示"一列"多条数据(比如所有联系人姓名),并能滚动、能选中、能删除,开始接触"数据 → 界面"的刷新思维。