ComBox 组件实现 教学总结
Table of Contents
- 一、这个模块到底在学什么
- 1. 选择层
- 2. 数据层
- 3. 联动层
- 4. 读取层
- 二、每个模块 / 函数的详细教学
- A. QComboBox 详细教学
- A.1 它是什么
- A.2 这次为什么用它
- A.3 最核心接口
- 1. addItem(...)
- 2. addItems(...)
- 3. clear()
- 4. currentText()
- 5. currentIndex()
- 6. currentData()
- B. on_comboBox_main_currentTextChanged(const QString &arg1) 详细教学
- B.1 它在做什么
- B.2 为什么这里用 arg1 很合适
- B.3 为什么先 clear()
- C. on_pushButton_clicked() 详细教学
- C.1 它在做什么
- C.2 为什么这一步很重要
- D. QMap 详细教学
- D.1 它是什么
- D.2 你这次分别怎么用
- QMap<QString, int> City_Zone
- QMap<QString, QList<QString>> cityMap
- D.3 为什么 QMap 适合这次场景
- D.4 最核心接口
- 1. insert(key, value)
- 2. value(key)
- 3. keys()
- D.5 一个你已经碰到但还没系统讲的问题:顺序
- E. QList<QString> 详细教学
- E.1 它是什么
- E.2 为什么这里不用 QMap
- E.3 最常见操作
- F. addItem() 里的“用户数据”详细教学
- F.1 为什么这很重要
- F.2 这次你虽然没读它,但概念已经出现了
- G. qDebug() 与中文输出问题
- G.1 为什么 qDebug() 更适合 Qt 项目
- G.2 这次你真正学到的不是“修乱码”,而是:
- 三、本模块新增模块的重点系统总结
- 1. QComboBox
- 定义
- 适合场景
- 常用接口
- 本次作用
- 2. QMap
- 定义
- 本次作用
- 常用接口
- 3. QList<QString>
- 定义
- 本次作用
- 常见用途
- 4. addItem(text, userData)
- 定义
- 本次作用
- 重要理解
- 5. currentTextChanged(const QString &)
- 定义
- 本次作用
- 四、这个模块最重要的知识点
- 1. QComboBox 是“离散选择控件”
- 2. 每个选项既有“显示文本”,也可以有“绑定数据”
- 3. 两级联动的核心不是 UI,而是映射关系
- 4. 上游选择变化时,下游候选项要重建
- 五、这个模块最容易踩的坑
- 易错点 1:对象名和槽函数名不匹配
- 易错点 2:忘记 clear()
- 易错点 3:误把 currentText() 当成唯一读取方式
- 易错点 4:把全局变量照抄进来
- 易错点 5:中文输出用 std::cout + toStdString() 乱码
- 六、你现在应该形成的理解
- 七、这一模块最值得记住的最小模板
Protected content
请输入课程内容访问密码
很好。现在进入 ComboBox:阶段 2(教学总结)。
先给结论:
这次真正要掌握的,不是“下拉框里能放几项”,而是 QComboBox 作为“选择器”和“状态入口”的作用。
这个模块比前面几个更接近真实业务界面,因为它已经不是单个控件自娱自乐,而是在做:
你的作业文档这一节也是按这个思路展开的:先演示 QComboBox 的基础增项方式,再演示带图标和用户数据的菜单项,最后落到“城市—区县”两级联动案例,并通过 currentText() 读取当前选项。
一、这个模块到底在学什么
这次可以拆成 4 层。
1. 选择层
QComboBox 的本质不是“显示文本”,而是:
从一组候选项中选一个当前值
所以它是一个离散选择控件。
2. 数据层
每个下拉项不只是一个可见文本,还可以绑定额外数据。
文档里已经提到:每个项除了显示内容外,还可以关联一个 QVariant 类型的数据。
也就是说:
这点非常重要。
3. 联动层
你这次做的是两级联动:
-
一级下拉框选中某城市
-
二级下拉框自动刷新成该城市对应区县
这是典型的:
4. 读取层
最终通过按钮读取当前一级和二级选项,拿到完整结果。
所以整个模块是在教你:
-
怎么构造选项
-
怎么响应选项变化
-
怎么读取当前状态
二、每个模块 / 函数的详细教学
下面按你要求,把这次新出现的模块、函数逐个详细讲清楚。
A. QComboBox 详细教学
A.1 它是什么
QComboBox 是 Qt 的下拉选择框控件。
它适合处理:
-
城市选择
-
年级/班级选择
-
类别选择
-
配置模式选择
-
任何“候选项有限、一次只选一个”的场景
和前面的控件对比:
-
QLineEdit:自由输入 -
QSpinBox:数值输入 -
QCheckBox:状态开关 -
QComboBox:从已有候选项中选一个
A.2 这次为什么用它
因为“城市—区县”就是标准的候选项选择场景:
-
城市不是用户自由输入
-
区县也不是随便打
-
它们应该来自程序预定义集合
所以用 QComboBox 最合适。
A.3 最核心接口
1. addItem(...)
添加单个项。
你这次实际用的是:
ui->comboBox_main->addItem(str, City_Zone.value(str));
它表示:
-
显示文本:
str -
绑定数据:
City_Zone.value(str)
文档里也明确展示了 addItem() 可传入文本、图标和用户数据。
2. addItems(...)
批量添加多个文本项。
虽然你这次最终代码没直接用,但文档前面演示了批量加入列表项的方式。
它适合在你已经有一个 QStringList 时直接灌进去。
3. clear()
清空所有项。
你这次一级和二级菜单都用了:
ui->comboBox_main->clear();
ui->comboBox_submain->clear();
这是联动场景里很常见的操作,因为“旧候选项”要先清掉,再填“新候选项”。
4. currentText()
获取当前选中项的显示文本。
你这次按钮槽里用到了:
QString one = ui->comboBox_main->currentText();
QString two = ui->comboBox_submain->currentText();
这是最常用的读取接口。
5. currentIndex()
获取当前选中项的下标。
这次你没直接用,但以后如果你只关心“第几个”而不是“文本是什么”,就会用它。
6. currentData()
获取当前项绑定的用户数据。
这次文档已经铺垫了“每个下拉项可绑定 QVariant 数据”这个概念。
你这次虽然没真正取 currentData(),但它是 QComboBox 很重要的高级接口。
B. on_comboBox_main_currentTextChanged(const QString &arg1) 详细教学
这是这次最核心的联动槽函数。
你写的是:
void MainWindow::on_comboBox_main_currentTextChanged(const QString &arg1)
{
ui->comboBox_submain->clear();
QList<QString> qtmp = cityMap.value(arg1);
for (int x = 0; x < qtmp.count(); x++)
{
ui->comboBox_submain->addItem(qtmp[x]);
}
}
B.1 它在做什么
它表示:
-
一级下拉框当前文本一变化
-
就拿这个文本
arg1去查映射表 -
找到对应区县列表
-
然后重建二级菜单
也就是:
B.2 为什么这里用 arg1 很合适
这和 QDial 模块里直接使用 value 参数是同一种思路:
-
信号已经把“当前值”作为参数传进来了
-
那就直接用,不必再重新
currentText()
所以这里:
const QString &arg1
就是当前选中的一级菜单文本。
B.3 为什么先 clear()
因为二级菜单是依赖一级菜单动态生成的。
如果不先清空,旧区县会残留,界面逻辑就错了。
所以联动场景里通常是:
C. on_pushButton_clicked() 详细教学
你这次最终修正后是用 qDebug() 输出:
void MainWindow::on_pushButton_clicked()
{
QString one = ui->comboBox_main->currentText();
QString two = ui->comboBox_submain->currentText();
qDebug().noquote() << one << "|" << two;
}
C.1 它在做什么
它的作用不是“触发联动”,而是:
在当前界面状态下,读取最终选择结果
这说明按钮在这里承担的是“确认/读取”角色,而不是“刷新”角色。
C.2 为什么这一步很重要
因为 GUI 编程最终都要落到一个核心问题:
用户当前到底选了什么?
QComboBox 的真正价值,不只是展示候选项,而是提供“当前选择”的读取入口。
D. QMap 详细教学
这是这次新增的最重要的数据结构之一。
D.1 它是什么
QMap<Key, Value> 是 Qt 的键值映射容器。
它的结构是:
你这次用了两种:
QMap<QString, int> City_Zone;
QMap<QString, QList<QString>> cityMap;
D.2 你这次分别怎么用
QMap<QString, int> City_Zone
表示:
例如:
-
"北京" -> 1 -
"上海" -> 2
这主要是给一级菜单 addItem(text, userData) 用的。
QMap<QString, QList<QString>> cityMap
表示:
例如:
-
"北京" -> ["大兴区","昌平区","东城区"] -
"上海" -> ["黄浦区","徐汇区","长宁区","杨浦区"]
这才是两级联动的核心映射表。
D.3 为什么 QMap 适合这次场景
因为你这里的需求本质是:
给我一个城市名,我要迅速找到它对应的区县列表
这正好是键值映射最典型的用途。
D.4 最核心接口
1. insert(key, value)
插入一组键值:
City_Zone.insert("北京", 1);
2. value(key)
根据 key 取 value:
QList<QString> qtmp = cityMap.value(arg1);
这是你这次联动里最关键的一句。
3. keys()
获取所有 key:
for (const QString &str : City_Zone.keys())
你用它来批量构造一级菜单。
D.5 一个你已经碰到但还没系统讲的问题:顺序
你前面虽然没报这个问题,但我已经提醒过你:
-
QMap的keys()返回顺序不一定等于你插入顺序 -
它更像按 key 的有序规则来给你结果
所以如果你将来非常在意“显示顺序”,就不能单纯依赖 QMap 插入顺序。
E. QList<QString> 详细教学
E.1 它是什么
QList<QString> 可以理解为:
一个字符串列表
你这次用它来存区县集合:
QList<QString>{"黄浦区", "徐汇区", "长宁区", "杨浦区"}
E.2 为什么这里不用 QMap
因为区县列表本身不需要“名称到值”的映射,只需要:
-
有多个元素
-
能顺序遍历
-
能逐个加到
comboBox_submain
所以用列表最自然。
E.3 最常见操作
你这次用到了:
qtmp.count()
qtmp[x]
以后你也会常用:
-
append(...) -
范围 for 循环
F. addItem() 里的“用户数据”详细教学
这是这次一个非常值得你建立概念的点。
你写的是:
ui->comboBox_main->addItem(str, City_Zone.value(str));
这里的第二个参数不是显示文本,而是绑定数据。
也就是说,这一行等于:
文档里明确说了:QComboBox 每个项可以绑定一个 QVariant 类型的数据。
F.1 为什么这很重要
因为真实项目里经常是这样:
-
用户看见的是“北京”
-
程序提交给后端的却是城市 ID:
1
所以:
这就是 addItem(text, userData) 的价值。
F.2 这次你虽然没读它,但概念已经出现了
你现在只是把用户数据绑上去了,还没真正去 currentData() 读出来。
但这个概念已经是 QComboBox 的核心高级能力之一了。
G. qDebug() 与中文输出问题
这次你还遇到了一个非常实际的问题:
用 std::cout << one.toStdString() 输出中文,在 Windows 控制台里乱码;改成 qDebug() 后正常。
G.1 为什么 qDebug() 更适合 Qt 项目
因为:
-
QString是 Qt 原生 Unicode 字符串 -
qDebug()能直接处理QString -
不需要你手动做窄字节编码转换
所以在 Qt 程序里,调试输出优先用:
qDebug()
通常比 std::cout 更稳,尤其涉及中文时。
G.2 这次你真正学到的不是“修乱码”,而是:
Qt 类型尽量用 Qt 的调试工具链处理。
也就是:
-
QString→ 优先qDebug() -
不要急着
toStdString()
三、本模块新增模块的重点系统总结
下面把这次新出现的东西再凝练成一份“系统总结”。
1. QComboBox
定义
下拉选择框控件
适合场景
-
从有限候选项中选一个
-
可做多级联动选择
-
可绑定额外用户数据
常用接口
-
addItem(...) -
addItems(...) -
clear() -
currentText() -
currentIndex() -
currentData()
本次作用
-
一级城市选择
-
二级区县选择
-
读取最终结果
2. QMap
定义
键值映射容器
本次作用
-
城市 -> 编号 -
城市 -> 区县列表
常用接口
-
insert() -
value() -
keys()
3. QList<QString>
定义
字符串列表
本次作用
保存某城市对应的多个区县
常见用途
-
一组候选项
-
一组标签
-
一组文件名
-
一组菜单文本
4. addItem(text, userData)
定义
往下拉框里添加一个项,同时绑定显示文本和业务数据
本次作用
让城市名和编号关联起来
重要理解
显示给用户看的文本,不一定是程序真正使用的数据
5. currentTextChanged(const QString &)
定义
当前选中文本改变时发出的信号
本次作用
作为一级菜单联动二级菜单的触发器
四、这个模块最重要的知识点
1. QComboBox 是“离散选择控件”
它不是文本框,不是数值框,而是“从候选项中选一个”。
2. 每个选项既有“显示文本”,也可以有“绑定数据”
这是 QComboBox 和普通菜单文本列表最大的区别之一。
3. 两级联动的核心不是 UI,而是映射关系
真正决定功能成立的不是“两个下拉框摆出来了”,而是你背后的:
4. 上游选择变化时,下游候选项要重建
也就是:
这是所有联动选择题的通用模式。
五、这个模块最容易踩的坑
易错点 1:对象名和槽函数名不匹配
例如:
-
comboBox_main -
on_comboBox_main_currentTextChanged(...)
必须完全匹配。
易错点 2:忘记 clear()
会导致二级菜单旧数据残留。
易错点 3:误把 currentText() 当成唯一读取方式
其实还有:
-
currentIndex() -
currentData()
以后要按需求选。
易错点 4:把全局变量照抄进来
文档原例把 QMap 和 QList 相关对象写成全局变量。
你这次已经改成成员变量,这是正确方向。
易错点 5:中文输出用 std::cout + toStdString() 乱码
你这次已经实际踩到了。
Qt 项目里优先用 qDebug() 处理 QString。
六、你现在应该形成的理解
做完这个模块,你应该明确:
-
QComboBox不只是下拉菜单,它是“选择器” -
选项文本和业务数据可以分离
-
两级联动本质是映射关系驱动的 UI 重建
-
QMap非常适合做这种“名称 -> 候选列表”的关联 -
Qt 工程里中文调试输出优先用
qDebug()
七、这一模块最值得记住的最小模板
你最值得记住的是这两段:
void MainWindow::on_comboBox_main_currentTextChanged(const QString &arg1)
{
ui->comboBox_submain->clear();
QList<QString> qtmp = cityMap.value(arg1);
for (int x = 0; x < qtmp.count(); x++)
{
ui->comboBox_submain->addItem(qtmp[x]);
}
}
和:
void MainWindow::on_pushButton_clicked()
{
QString one = ui->comboBox_main->currentText();
QString two = ui->comboBox_submain->currentText();
qDebug().noquote() << one << "|" << two;
}
它们分别代表:
以及
下一步按新流程,应该进入 ProgressBar 阶段 1:实现 + 运行验证。