走进Qt--Qt 常用输入控件详解

73 阅读13分钟

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中分组布局(隐式分组)

适用场景

  • 快速拖拽设计界面
  • 不需要手写分组代码
操作步骤
  1. 在Qt Designer中拖入两个 Group Box(或 QWidget
  2. 分别在不同容器内放置 QRadioButton
  3. 生成的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)获取 / 设置当前状态(可取 CheckedUncheckedPartiallyChecked

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(","));

}

image.png

image.png

image.png


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));
     });

image.png


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(浮点数输入框)

QDoubleSpinBoxQSpinBox 的浮点数版本,专为精确的数值输入设计。

与QSpinBox的区别

特性QSpinBoxQDoubleSpinBox
数据类型整数 (int)浮点数 (double)
默认范围0~990.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. 综合示例:用户信息输入表单

该案例整合了五种输入控件,点击"提交"按钮后汇总用户选择信息并显示。

功能概述

  1. 表单包含
    • 性别选择(QRadioButton
    • 兴趣爱好多选(QCheckBox
    • 城市选择(QComboBox
    • 年龄输入(QSpinBox+QSlider
    • 身高输入(QDoubleSpinBox
  2. 提交后:弹窗显示所有选择信息

代码实现

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);
    });

界面效果

image.png

image.png


9. 总结

这些控件虽然都属于“输入组件”,但在使用时各有侧重,以下是一些实践建议与适用场景参考:

控件适用场景使用建议
QRadioButton多个选项中选择一个(如性别)搭配 QButtonGroup 实现单选组
QCheckBox多项可选(如兴趣爱好)可配合全选/反选逻辑、状态显示
QComboBox从下拉列表中选择(如省市)支持数据绑定、自定义显示、动态更新
QSpinBox / QDoubleSpinBox数值输入(整数或小数)设置范围、步长、特殊文本(如“未选择”)
QSlider数值滑动调整(如音量、进度)可搭配标签/实时值显示使用