1. 前言
在开发图形界面应用时,用户输入控件扮演着至关重要的角色。无论是填写表单、调整参数,还是配置用户选项,Qt 提供了一系列强大且易于使用的控件,帮助开发者快速构建高效、友好的交互界面。
本篇文章将重点介绍 Qt 中几类常用的输入型控件,包括:
QRadioButton
(单选按钮)
QCheckBox
(复选框)
QComboBox
(下拉框)
QSpinBox
(整数微调框)
QDoubleSpinBox
(浮点数输入框)
QSlider
(滑动条)
我们将通过简单易懂的示例,展示它们的基本用法、信号响应方式及常见使用场景,并在文章末尾构建一个小型的设置面板综合示例,帮助你更好地掌握这些控件的实际应用。
由于在前面的文章中已经写了QLineEdit
,这里就不在讲解该控件。
2. QRadioButton(单选按钮)
2.1 简介
QRadioButton
是 Qt 中的单选按钮控件,常用于多个选项中只能选择一个的场景。例如:选择性别、支付方式、模式切换等。
多个 QRadioButton
放在同一父容器或布局中,系统会自动将它们视为一组,实现互斥选择。
2.2 基本用法
创建与设置:
QRadioButton *radio1 = new QRadioButton("选项A");
QRadioButton *radio2 = new QRadioButton("选项B");
radio1->setChecked(true); // 设置默认选中
2.3 单选组管理
多个QRadioButton
需通过QButtonGroup
实现互斥:
QButtonGroup *genderGroup = new QButtonGroup(this);
genderGroup->addButton(radio1, 1); // 参数1:按钮对象,参数2:ID(可选)
genderGroup->addButton(radio2, 2);
// 通过ID获取选中项
int selectedId = genderGroup->checkedId(); // 返回1或2
2.4 信号槽响应
connect(radio1, &QRadioButton::toggled, this, [](bool checked){
if (checked) {
qDebug() << "选项A 被选中";
}
});
2.5 分组使用
在Qt中,单选按钮(QRadioButton) 默认会互斥选择(同一时间只能选一个)。要实现多组独立选择,必须显式分组。以下是三种常用分组方法及注意事项。
1.使用QButtonGroup(逻辑分组)
适用场景:
- 不需要额外UI容器,仅需逻辑分组
- 适合动态生成的选项
代码示例
// 创建按钮组(不涉及UI布局)
QButtonGroup *genderGroup = new QButtonGroup(this);
QButtonGroup *ageGroup = new QButtonGroup(this);
// 添加单选按钮到不同组
genderGroup->addButton(new QRadioButton("男"));
genderGroup->addButton(new QRadioButton("女"));
ageGroup->addButton(new QRadioButton("成年"));
ageGroup->addButton(new QRadioButton("未成年"));
// 获取选中项
int selectedGenderId = genderGroup->checkedId(); // 返回分配的ID(默认-1/0/1...)
QString selectedAge = ageGroup->checkedButton()->text(); // 返回选中按钮文本
QButtonGroup
本身是逻辑分组控件,不会直接显示在界面上。还是需要将控件布局在窗口中才会显示。
优点:
- 纯逻辑控制,不依赖UI层级
- 适合动态管理(如从数据库加载选项)
2.使用 QGroupBox(UI容器分组)
适用场景:
- 需要视觉分组(如带标题的框)
- 适合静态选项布局
代码示例
// 性别分组
QGroupBox *genderBox = new QGroupBox("性别");
QHBoxLayout *genderLayout = new QHBoxLayout(genderBox); // 父控件设为GroupBox
genderLayout->addWidget(new QRadioButton("男"));
genderLayout->addWidget(new QRadioButton("女"));
// 年龄分组
QGroupBox *ageBox = new QGroupBox("年龄");
QHBoxLayout *ageLayout = new QHBoxLayout(ageBox);
ageLayout->addWidget(new QRadioButton("成年"));
ageLayout->addWidget(new QRadioButton("未成年"));
// 添加到主布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(genderBox);
mainLayout->addWidget(ageBox);
优点:
- 自动实现组内互斥(因父控件不同)
- 提升UI友好性(带分组标题)
3.在Qt Designer中分组布局(隐式分组)
适用场景:
- 快速拖拽设计界面
- 不需要手写分组代码
操作步骤
- 在Qt Designer中拖入两个 Group Box(或
QWidget
) - 分别在不同容器内放置
QRadioButton
- 生成的UI文件会自动维护分组关系
将按钮放在不同的布局中也可以实现分组
核心原因:Qt Designer 的隐式分组机制
当你在 Qt Designer 中拖放 QRadioButton
到不同布局时,Designer 会自动为不同容器内的按钮创建隐式分组。
优点:
- 无需手写代码,Designer自动处理父控件关系
3. QCheckBox(复选框)
复选框(QCheckBox
)是GUI开发中常用的输入控件,允许用户选择多个选项(与单选按钮相反)。
3.1 基本用法
QCheckBox *check1 = new QCheckBox("接收邮件通知");
check1->setChecked(true); // 设置默认勾选状态
3.2 常用方法
方法 | 说明 |
---|---|
setChecked(bool) | 设置是否选中 |
isChecked() | 判断是否选中 |
setTristate(bool) | 启用三态复选框(含部分选中状态) |
checkState() / setCheckState(Qt::CheckState) | 获取 / 设置当前状态(可取 Checked 、Unchecked 、PartiallyChecked ) |
3.3 三态复选框
QCheckBox
支持第三种状态:部分选中(Partially Checked),常用于“全选/部分选”场景。
3.3.1 启用三态模式
QCheckBox *checkBox = new QCheckBox("权限设置", this);
checkBox->setTristate(true); // 启用三态
checkBox->setCheckState(Qt::PartiallyChecked); // 设为部分选中
3.3.2 三态枚举值
状态 | 枚举值 | 说明 |
---|---|---|
未选中 | Qt::Unchecked | 对应 false |
选中 | Qt::Checked | 对应 true |
部分选中 | Qt::PartiallyChecked | 中间状态 |
3.3.3 获取三态状态
Qt::CheckState state = checkBox->checkState();
if (state == Qt::PartiallyChecked) {
qDebug() << "部分权限已启用";
}
3.4 信号与槽
QCheckBox
提供两种状态变化信号:
stateChanged(int)
:三态变化时触发(参数为Qt::CheckState
枚举值)toggled(bool)
:仅两态变化时触发(参数为true/false
)
监听状态变化
// 三态信号(推荐)
connect(checkBox, &QCheckBox::stateChanged, [](int state) {
qDebug() << "新状态:" << state; // 0=未选中, 1=部分选中, 2=选中
});
// 两态信号(兼容旧代码)
connect(checkBox, &QCheckBox::toggled, [](bool checked) {
qDebug() << "是否选中:" << checked;
});
3.5 应用示例
复选框组联动(全选/反选)
//主布局
QVBoxLayout* mainLayout = new QVBoxLayout(this);
//1.全选复选框
QCheckBox* selectAll = new QCheckBox("全选", this);
mainLayout->addWidget(selectAll);
//2. 添加子复选框
QList<QCheckBox*> itemBoxes;
for (int i = 1; i <= 5; ++i) {
QCheckBox* box = new QCheckBox(QString("选项 %1").arg(i), this);
itemBoxes.append(box);
mainLayout->addWidget(box);
}
//3. 反选按钮
QPushButton* inverBtn = new QPushButton("反选", this);
mainLayout->addWidget(inverBtn);
//4.状态显示标签
QLabel* statusLabel = new QLabel("当前状态:未选中", this);
mainLayout->addWidget(statusLabel);
//点击"全选"时联动所有子项
connect(selectAll, &QCheckBox::clicked, [=](bool checked) {
for (QCheckBox* box : itemBoxes) {
box->blockSignals(true); //临时阻塞信号
box->setChecked(checked);
box->blockSignals(false);
}
updateStatusLabel(statusLabel,itemBoxes);
});
//子项变化时更新"全选"状态
for (QCheckBox* box : itemBoxes) {
connect(box, &QCheckBox::stateChanged, [=]() {
//更新全选状态
int checkedCount = std::count_if(itemBoxes.begin(), itemBoxes.end(), [](QCheckBox* b) {
return b->isChecked();
});
selectAll->blockSignals(true);
selectAll->setChecked(checkedCount == itemBoxes.size());
selectAll->blockSignals(false);
updateStatusLabel(statusLabel, itemBoxes);
});
}
//点击 "反选"选项
connect(inverBtn, &QPushButton::clicked, [=]() {
// 只反选子项,不自动更新全选
for (QCheckBox* box : itemBoxes) {
box->setChecked(!box->isChecked());
}
// 手动更新全选状态
int checkedCount = std::count_if(itemBoxes.begin(), itemBoxes.end(),
[](QCheckBox* b) { return b->isChecked(); });
selectAll->setChecked(checkedCount == itemBoxes.size());
updateStatusLabel(statusLabel, itemBoxes);
});
}
void CheckBoxDemo::updateStatusLabel(QLabel* label, const QList<QCheckBox*>& boxes)
{
QStringList selectedItems;
for (QCheckBox* box : boxes) {
if (box->isChecked()) {
selectedItems << box->text();
}
}
label->setText(selectedItems.isEmpty() ? "当前状态:未选中" : "已选中 " + selectedItems.join(","));
}
4. QComboBox(下拉框)
QComboBox
是Qt中常用的下拉选择控件,支持单选、可编辑、动态加载等特性。
4.1 基础用法
创建与添加选项
QComboBox *comboBox = new QComboBox(this);
// 添加单个选项
comboBox->addItem("苹果");
comboBox->addItem("香蕉");
// 批量添加选项
QStringList fruits = {"橙子", "葡萄", "西瓜"};
comboBox->addItems(fruits);
// 插入选项到指定位置
comboBox->insertItem(2, "芒果"); // 在索引2处插入
4.2 常用方法
方法 | 作用 |
---|---|
currentIndex() | 返回当前选项的索引(从0开始) |
currentText() | 返回当前选项的文本 |
setCurrentIndex(int) | 通过索引设置当前选项 |
setCurrentText(QString) | 通过文本设置当前选项(需完全匹配) |
count() | 获取选项总数 |
clear() | 清空所有选项 |
4.3 可编辑下拉框
comboBox->setEditable(true); // 允许用户输入
comboBox->setInsertPolicy(QComboBox::InsertAtTop); // 新选项插入位置
4.4 信号与事件
常用信号
信号 | 触发时机 |
---|---|
currentIndexChanged(int) | 选项索引变化时 |
currentTextChanged(QString) | 选项文本变化时 |
editTextChanged(QString) | 可编辑模式下文本变化时 |
信号槽连接
connect(comboBox, &QComboBox::currentIndexChanged, [=](int index){
qDebug() << "当前选中项索引:" << index;
qDebug() << "当前选中项文本:" << comboBox->itemText(index);
});
4.4 示例:省市选择
QHBoxLayout* mainLayout = new QHBoxLayout(this);
QComboBox* provinceCombo = new QComboBox;
provinceCombo->addItems({ "北京市","上海市","江苏省","苏州市" });
//省市下拉框
QComboBox* cityCombo = new QComboBox;
QHash<QString, QStringList> cityData = {
{"北京市",{"东城区","西城区"}},
{"上海市",{"黄浦区","徐汇区"}},
{"江苏省",{"苏州市","南京市"}},
{"苏州市",{"姑苏区","相城区"}}
};
mainLayout->addWidget(provinceCombo);
mainLayout->addWidget(cityCombo);
//省级变化时更新市选项
connect(provinceCombo, &QComboBox::currentTextChanged, [=](const QString& province) {
cityCombo->clear();
cityCombo->addItems(cityData.value(province));
});
5. QSpinBox(数值输入框)
QSpinBox
是Qt中用于整数输入的专用控件,支持范围限制、步长调整、前缀后缀等特性。
5.1 基本用法
创建与基本设置
QSpinBox *spinBox = new QSpinBox(this);
spinBox->setRange(0, 100); // 取值范围:0~100
spinBox->setValue(50); // 默认值
spinBox->setSingleStep(5); // 步长(点击增减按钮时的变化量)
显示格式定制
spinBox->setPrefix("¥ "); // 前缀(如货币符号)
spinBox->setSuffix(" 元"); // 后缀(如单位)
// 显示效果:¥ 50 元
禁止键盘输入
spinBox->setKeyboardTracking(false); // 关闭实时响应键盘输入
spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); // 隐藏增减按钮,键盘↑↓调整
5.2 常用方法
方法 / 信号 | 说明 |
---|---|
setRange(min, max) | 设置允许的整数范围 |
setSingleStep(step) | 设置步长 |
value() / setValue() | 获取或设置当前值 |
setPrefix("¥") | 在值前加上前缀,例如货币符号 |
setSuffix(" 个") | 在值后添加单位 |
valueChanged(int) | 当前值变化时发出的信号 |
5.3信号与事件处理
值变化监听
// 值变化时触发(参数为int)
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged),
[](int value) {
qDebug() << "当前值:" << value;
});
// 文本变化时触发(参数为QString)
connect(spinBox, &QSpinBox::textChanged,
[](const QString &text) {
qDebug() << "当前文本:" << text;
});
编辑完成事件
connect(spinBox, &QSpinBox::editingFinished,
[]() {
qDebug() << "用户完成编辑";
});
5.4 其他功能
特殊值显示
spinBox->setRange(-1, 100);
spinBox->setSpecialValueText("未选择"); // 当值=-1时显示文本
自定义验证
// 只允许输入偶数
spinBox->setValidator(new QIntValidator(0, 100, this));
connect(spinBox, &QSpinBox::textChanged, [=](const QString &text) {
int val = text.toInt();
if (val % 2 != 0) {
spinBox->setValue(val - 1); // 自动修正为偶数
}
});
十六进制显示
spinBox->setDisplayIntegerBase(16); // 显示为十六进制
spinBox->setPrefix("0x"); // 添加前缀
// 显示效果:0x1f
5.5示例:年龄输入
QSpinBox *ageSpinBox = new QSpinBox(this);
ageSpinBox->setRange(1, 120); // 合理年龄范围
ageSpinBox->setSuffix(" 岁");
ageSpinBox->setSpecialValueText("年龄未知"); // 值=0时显示
6. QDoubleSpinBox(浮点数输入框)
QDoubleSpinBox
是 QSpinBox
的浮点数版本,专为精确的数值输入设计。
与QSpinBox的区别
特性 | QSpinBox | QDoubleSpinBox |
---|---|---|
数据类型 | 整数 (int ) | 浮点数 (double ) |
默认范围 | 0~99 | 0.0~99.99 |
精度控制 | 不支持 | setDecimals() 控制小数位 |
科学计数法 | 不支持 | 支持 (setNotation() ) |
6.1 基础用法
创建与精度设置
QDoubleSpinBox *doubleSpin = new QDoubleSpinBox(this);
doubleSpin->setRange(0.0, 100.0); // 设置范围
doubleSpin->setValue(50.5); // 默认值
doubleSpin->setSingleStep(0.1); // 步长
doubleSpin->setDecimals(2); // 显示2位小数(自动四舍五入)
科学计数法模式
doubleSpin->setNotation(QDoubleSpinBox::ScientificNotation); // 科学计数法
// 显示效果:5.05e+1
6.2 信号与验证
值变化信号
// 值变化信号(参数为double)
connect(doubleSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
[](double value) {
qDebug() << "当前值:" << value;
});
// 文本变化信号(含格式化的前缀/后缀)
connect(doubleSpin, &QDoubleSpinBox::textChanged,
[](const QString &text) {
qDebug() << "格式化文本:" << text;
});
输入验证
// 限制输入范围(底层自动处理)
doubleSpin->setMinimum(0.0); // 不允许负数
// 自定义验证(如禁止输入π的近似值)
connect(doubleSpin, &QDoubleSpinBox::editingFinished, [=]() {
if (qFuzzyCompare(doubleSpin->value(), 3.14)) {
doubleSpin->setValue(0.0); // 重置为0
QMessageBox::warning(this, "错误", "禁止输入π的近似值!");
}
});
6.3 示例:货币输入
QDoubleSpinBox *priceInput = new QDoubleSpinBox(this);
priceInput->setRange(0.0, 999999.99);
priceInput->setPrefix("¥ ");
priceInput->setDecimals(2); // 强制2位小数
priceInput->setSingleStep(0.5); // 支持0.5元调整
7. QSlider(滑动条)
QSlider
是Qt中用于通过滑动输入数值的控件,支持水平或垂直方向,常用于音量控制、亮度调节等场景。
7.1 基础用法
创建与方向设置
QSlider *slider = new QSlider(this);
// 设置方向(默认为水平)
slider->setOrientation(Qt::Horizontal); // 或 Qt::Vertical
// 设置取值范围和当前值
slider->setRange(0, 100); // 最小值0,最大值100
slider->setValue(50); // 初始值
7.2 常用方法
方法/属性 | 作用 |
---|---|
setTickPosition() | 刻度位置(见下方详解) |
setSingleStep() | 键盘方向键的步长(默认1) |
setPageStep() | PageUp/PageDown的步长(默认10) |
setTracking() | 是否实时触发值变化信号(默认true) |
刻度位置选项
slider->setTickPosition(QSlider::TicksBelow); // 刻度在下方/右侧
// 可选值:
// QSlider::NoTicks // 无刻度
// QSlider::TicksAbove // 上方/左侧(垂直滑块)
// QSlider::TicksBelow // 下方/右侧
// QSlider::TicksBothSides // 两侧均有刻度
7.3 信号与事件
值变化信号
// 值变化时触发(参数为int)
connect(slider, &QSlider::valueChanged,
[](int value) {
qDebug() << "当前值:" << value;
});
// 滑块释放时触发(适合耗时操作)
connect(slider, &QSlider::sliderReleased,
[=]() {
qDebug() << "最终值:" << slider->value();
});
自定义鼠标事件
// 点击跳转到指定位置(默认需拖动滑块)
slider->setProperty("clickPosition", true);
slider->installEventFilter(this); // 需重写eventFilter
// 在父类中实现:
bool eventFilter(QObject *obj, QEvent *event) override {
if (obj == slider && event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
int value = QStyle::sliderValueFromPosition(
slider->minimum(), slider->maximum(),
mouseEvent->pos().x(), slider->width());
slider->setValue(value);
return true;
}
return QWidget::eventFilter(obj, event);
}
7.4 示例: 音量控制器
QSlider *volumeSlider = new QSlider(Qt::Horizontal, this);
volumeSlider->setRange(0, 100);
QLabel *volumeLabel = new QLabel("50", this);
connect(volumeSlider, &QSlider::valueChanged,
[=](int value) {
volumeLabel->setText(QString::number(value));
});
// 布局
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(new QLabel("音量:"));
layout->addWidget(volumeSlider);
layout->addWidget(volumeLabel);
8. 综合示例:用户信息输入表单
该案例整合了五种输入控件,点击"提交"按钮后汇总用户选择信息并显示。
功能概述
- 表单包含:
- 性别选择(
QRadioButton
) - 兴趣爱好多选(
QCheckBox
) - 城市选择(
QComboBox
) - 年龄输入(
QSpinBox
+QSlider
) - 身高输入(
QDoubleSpinBox
)
- 性别选择(
- 提交后:弹窗显示所有选择信息
代码实现
setWindowTitle("用户信息表单");
setFixedSize(400, 400);
//主布局
QVBoxLayout* mainLayout = new QVBoxLayout(this);
//性别选择(QRadioButton)
QGroupBox* genderGroup = new QGroupBox("性别", this);
QHBoxLayout* genderLayout = new QHBoxLayout(genderGroup);
QRadioButton* maleRadio = new QRadioButton("男", genderGroup);
QRadioButton* femaleRadio = new QRadioButton("女", genderGroup);
maleRadio->setChecked(true); //默认选中
genderLayout->addWidget(maleRadio);
genderLayout->addWidget(femaleRadio);
//兴趣爱好(QCheckBox)
QGroupBox* hobbyGroup = new QGroupBox("兴趣爱好", this);
QVBoxLayout* hobbyLayout = new QVBoxLayout(hobbyGroup);
QCheckBox* sportsCheck = new QCheckBox("运动", hobbyGroup);
QCheckBox* musicCheck = new QCheckBox("音乐", hobbyGroup);
QCheckBox* readingCheck = new QCheckBox("阅读", hobbyGroup);
hobbyLayout->addWidget(sportsCheck);
hobbyLayout->addWidget(musicCheck);
hobbyLayout->addWidget(readingCheck);
//城市选择(QComBox)
QComboBox* cityCombo = new QComboBox(this);
cityCombo->addItems({ "北京","上海","广州","深圳" });
cityCombo->setCurrentIndex(0); //默认选择第一个
//年龄输入(QSpinBox+QSlider 联动)
QHBoxLayout* ageLayout = new QHBoxLayout();
QLabel* ageLabel = new QLabel("年龄:");
QSpinBox* ageSpin = new QSpinBox(this);
QSlider* ageSlider = new QSlider(Qt::Horizontal,this);
ageSpin->setRange(1, 120);
ageSpin->setValue(18); //默认值
ageSpin->setSuffix("岁");
ageSlider->setRange(1, 120);
ageSlider->setValue(18);
ageSlider->setFixedWidth(200); //设置滑动条宽度
connect(ageSpin, QOverload<int>::of(&QSpinBox::valueChanged), ageSlider, &QSlider::setValue);
connect(ageSlider, &QSlider::valueChanged, ageSpin, &QSpinBox::setValue);
ageLayout->addWidget(ageLabel);
ageLayout->addWidget(ageSpin);
ageLayout->addWidget(ageSlider);
//身高输入(QDoubleSpinBox)
QDoubleSpinBox* heightSpin = new QDoubleSpinBox(this);
heightSpin->setRange(0.5, 2.5);
heightSpin->setValue(1.80);
heightSpin->setDecimals(2);
heightSpin->setSuffix("米");
//提交按钮
QPushButton* submitBtn = new QPushButton("提交信息", this);
//添加到主布局
mainLayout->addWidget(genderGroup);
mainLayout->addWidget(hobbyGroup);
mainLayout->addWidget(new QLabel("居住城市:"));
mainLayout->addWidget(cityCombo);
mainLayout->addLayout(ageLayout);
mainLayout->addWidget(new QLabel("身高:"));
mainLayout->addWidget(heightSpin);
mainLayout->addWidget(submitBtn);
//连接信号
connect(submitBtn, &QPushButton::clicked, [=]() {
QString info = "您提交的信息如下: \n\n";
//性别
info += "性别:";
info += maleRadio->isChecked() ? "男" : "女";
info += "\n";
//兴趣爱好
info += "兴趣爱好: ";
QStringList hobbies;
if (sportsCheck->isChecked()) hobbies << "运动";
if (musicCheck->isChecked()) hobbies << "音乐";
if (readingCheck->isChecked()) hobbies << "阅读";
info += hobbies.isEmpty() ? "无" : hobbies.join("、");
info += "\n";
//城市
info += "城市: " + cityCombo->currentText() + "\n";
//年龄
info += QString("年龄: %1 岁\n").arg(ageSpin->value());
//身高
info += QString("身高: %1 米\n").arg(heightSpin->value());
//显示信息
QMessageBox::information(this,"信息汇总", info);
});
界面效果
9. 总结
这些控件虽然都属于“输入组件”,但在使用时各有侧重,以下是一些实践建议与适用场景参考:
控件 | 适用场景 | 使用建议 |
---|---|---|
QRadioButton | 多个选项中选择一个(如性别) | 搭配 QButtonGroup 实现单选组 |
QCheckBox | 多项可选(如兴趣爱好) | 可配合全选/反选逻辑、状态显示 |
QComboBox | 从下拉列表中选择(如省市) | 支持数据绑定、自定义显示、动态更新 |
QSpinBox / QDoubleSpinBox | 数值输入(整数或小数) | 设置范围、步长、特殊文本(如“未选择”) |
QSlider | 数值滑动调整(如音量、进度) | 可搭配标签/实时值显示使用 |