开篇介绍:
hello 大家,本篇博客我们来学习QRadioButton常见属性以及QButtonGroup。
在 Qt 界面开发中,我们经常会遇到 "从多个选项中选择一个" 的场景 ------ 比如填写问卷时的性别选择(男 / 女 / 其他)、软件设置里的主题选择(浅色 / 深色 / 跟随系统)、游戏里的难度选择(简单 / 普通 / 困难)。这种 "多选一" 的交互需求,Qt 专门为我们提供了一个核心控件来实现,它就是 QRadioButton(单选按钮)。
很多新手刚接触 QRadioButton 时,只会简单地拖到界面上,却不知道它还有很多强大的属性和信号可以让单选逻辑更清晰、交互更流畅;也不知道当界面上有多组独立的单选需求时(比如同时选 "性别" 和 "学历"),该怎么让组内互斥、组间独立。
别担心!这篇文章我会结合最常用的核心属性(checkable、checked、autoExclusive)、四个核心信号(clicked、pressed、released、toggled),以及专门用来分组的 QButtonGroup 类进行解析~~~
话不多说,我们正式开始!
第一章 先搞懂基础:QRadioButton 的继承关系
在讲具体属性之前,我们必须先搞懂 QRadioButton 的 "身世"------ 也就是它的继承关系,这能帮我们理解为什么它能使用那么多属性。
1.1 继承关系的通俗解释
QRadioButton 并不是 "凭空出现" 的,它和我们之前学过的 QPushButton 一样,有一个清晰的继承链条:
QRadioButton → QAbstractButton(抽象类) → QWidget(所有界面控件的基类)
我用一个通俗的类比来解释这个继承关系:
- QWidget :就像 "所有家具的基类",它定义了所有家具都有的通用能力 ------ 比如 "能放在房间里""有大小和位置""能被看到"。对应到 Qt 中,QWidget 定义了所有控件都有的通用属性 ------ 比如
font(字体)、styleSheet(样式表)、toolTip(悬停提示)、geometry(位置和大小)等,这些属性 QRadioButton 都能直接使用,用法和 QPushButton、QLabel 完全一致,本文就不再重复讲解这些通用属性了,重点放在 QRadioButton 独有的、和单选逻辑相关的属性上。 - QAbstractButton :就像 "所有按钮的基类模板",它是一个抽象类(通俗理解就是 "不能直接拿来用的模板,只能用来给子类提供功能"),它定义了所有按钮都有的核心能力 ------ 比如 "能显示文本""能显示图标""能被点击""能设置选中状态"。QRadioButton 的核心功能,几乎都是由这个父类提供的。
- QRadioButton :就像 "具体的单选题选项",它继承了 QWidget 和 QAbstractButton 的所有能力,并且在此基础上,默认开启了 "排他性"(
autoExclusive),专门用来实现 "多选一" 的单选逻辑。
这个继承层级,我们在 Qt Designer 的类查看器中也能直观地看到。
1.2 继承关系带来的两个核心结论
理解了继承关系,我们就能得出两个非常重要的结论,这两个结论能帮我们少走很多弯路:
- QWidget 和 QAbstractButton 的所有属性,QRadioButton 都能用 :之前我们学过的 QPushButton 的属性(比如
text、icon、iconSize、shortcut、autoRepeat等),QRadioButton 都能直接使用,用法完全一致,比如给 QRadioButton 设置文本用setText(),设置图标用setIcon(),和 QPushButton 一模一样。 - Qt 的 API 设计风格非常统一 :所有属性的访问方式都是一样的 ------
- 获取属性值 :如果是布尔类型的属性,调用「is 属性名 ()」方法(比如获取选中状态调用
isChecked());如果是其他类型,调用「属性名 ()」方法(比如获取文本调用text()); - 设置属性值 :调用「set 属性名 (参数)」方法(比如设置选中状态调用
setChecked(true))。
- 获取属性值 :如果是布尔类型的属性,调用「is 属性名 ()」方法(比如获取选中状态调用
记住这两个结论,我们接下来的学习就会轻松很多!
第二章 QAbstractButton 核心属性详解(QRadioButton 的单选逻辑来源)
QAbstractButton 是所有按钮的父类,它定义了三个和 QRadioButton 单选逻辑强相关的核心属性 ------checkable(是否可选中)、checked(是否已选中)、autoExclusive(是否排他)。这三个属性是实现单选的基础,我们逐个来讲,每个属性都讲透 "是什么""为什么用""怎么用""API 详解""代码示例""注意事项"。
2.1 属性一:checkable(是否可选中)------ checked 属性生效的前置条件
2.1.1 属性的核心定义
checkable 属性用于控制单选按钮是否具备 "被选中 / 取消选中" 的交互能力,是 checked 属性生效的核心前置条件。
通俗理解:checkable 就像 "单选题选项的开关"------ 如果开关打开(checkable=true),这个选项可以被点击选中;如果开关关闭(checkable=false),这个选项就变成了 "纯展示的文本",哪怕你点它,它也不会被选中,checked 属性始终是 false。
QRadioButton 作为专门的单选按钮,默认将 checkable 设为 true,无需手动配置即可满足常规单选场景需求。
2.1.2 数据类型
bool 类型,true 表示具备可选中能力,false 表示不具备。
2.1.3 关联 API 详解(逐词逐句,零模糊)
checkable 属性的操作 API 遵循 Qt 统一设计风格,支持获取当前状态、设置新状态两种核心操作:
1. 获取当前可选中状态:bool isCheckable () const
函数原型:
bool QAbstractButton::isCheckable() const;
逐词逐句底层解析:
bool:函数的返回值类型,返回按钮是否具备可选中能力;QAbstractButton:::说明这个函数是QAbstractButton类的成员函数,所有继承自 QAbstractButton 的类(包括 QRadioButton、QPushButton、QCheckBox)都能调用;isCheckable():函数名,很直观,就是 "是否可选中" 的意思,布尔类型的属性,Qt 通常用isXxx()来获取;- 最后的
const:说明这个函数是常成员函数 ------ 它只会读取按钮的可选中状态,不会修改按钮的任何状态,所以你可以在const的成员函数里调用它,提高代码的安全性和正确性。
返回值说明:
- 如果按钮已经设置过可选中能力,返回当前生效的状态;
- QRadioButton 默认返回
true(具备可选中能力)。
调用示例:
// 获取"男"单选按钮的可选中状态,并存储到变量中
bool canCheck = ui->radioButton_male->isCheckable();
// 可以用 qDebug() 打印出来,方便调试
qDebug() << "男单选按钮是否可选中:" << canCheck;
2. 设置可选中状态:void setCheckable (bool enable)
函数原型:
void QAbstractButton::setCheckable(bool enable);
逐词逐句底层解析:
void:函数没有返回值,只是执行 "设置可选中状态" 的操作;QAbstractButton:::同样说明这是 QAbstractButton 的成员函数;setCheckable():函数名,"设置可选中状态" 的意思;bool enable:函数的入参,enable是一个布尔值,true表示开启可选中能力,false表示关闭。
参数说明:
enable:要设置的新状态,true开启可选中能力,false关闭;- 关闭可选中能力后,按钮仅能作为普通文本按钮显示,无法通过点击或代码修改选中状态(
checked属性始终为false)。
生效规则:
- 调用后立即生效,按钮界面会实时更新状态;
- 关闭可选中能力后,
checked属性的修改操作将失效,哪怕你调用setChecked(true),按钮也不会被选中。
调用示例:
// 开启可选中能力(QRadioButton 默认状态,无需手动设置)
ui->radioButton_male->setCheckable(true);
// 关闭可选中能力,按钮变为不可选状态(比如"其他"选项暂时不可用)
ui->radioButton_other->setCheckable(false);
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们就来学习QRadioButton的checkable属性和checked属性
//这两个属性也是很简单,checkable属性就是控制该选项能不能被选择,而checked属性就是看该选项有没有被选择罢了
//是很简单的
/**
* @property QRadioButton::checkable
* @brief QRadioButton的可选中能力控制属性(继承自QAbstractButton)
* @details 该属性用于控制单选按钮是否具备"被选中/取消选中"的交互能力,是checked属性生效的核心前置条件;
* 若该属性为false,单选按钮仅能作为普通文本按钮显示,无法通过点击或代码修改选中状态(checked属性始终为false);
* 若该属性为true,单选按钮可响应点击操作切换选中状态,也可通过代码手动设置checked属性,是实现单选交互的基础。
* QRadioButton默认将该属性设为true,无需手动配置即可满足常规单选场景需求。
*
* 【关联API详解】
* 1. bool isCheckable() const
* - 功能:获取单选按钮当前的可选中能力状态
* - 返回值:bool类型;true表示具备可选中能力,false表示无选中能力;QRadioButton默认返回true
* - 调用示例:
* // 读取"男"单选按钮的可选中状态
* bool canCheck = ui->radioBtnMale->isCheckable();
*
* 2. void setCheckable(bool enable)
* - 功能:开启或关闭单选按钮的可选中能力
* - 参数:enable - 布尔类型,true为开启可选中能力,false为关闭
* - 生效规则:调用后立即生效,关闭可选中能力后,checked属性的修改操作将失效
* - 调用示例:
* // 关闭可选中能力,按钮变为不可选状态
* ui->radioBtnMale->setCheckable(false);
* // 恢复可选中能力(默认状态)
* ui->radioBtnMale->setCheckable(true);
*
* 【关键注意事项】
* 1. 前置依赖:该属性是checked属性生效的必要条件,若checkable=false,调用setChecked()修改选中状态不会产生任何效果;
* 2. 默认状态:QRadioButton初始化时默认开启可选中能力(checkable=true),仅在需将单选按钮作为"纯展示文本"时才需关闭;
* 3. 交互表现:关闭可选中能力后,单选按钮的点击操作不会触发toggled()信号,也不会改变界面显示样式。
*
* ---
*
* @property QRadioButton::checked
* @brief QRadioButton的选中状态标识属性(继承自QAbstractButton)
* @details 该属性用于标识单选按钮当前是否处于"被选中"状态,仅在checkable属性为true时生效;
* 选中状态的QRadioButton会在界面上显示标志性的圆点指示器,未选中状态则无该标识,是用户区分选中项的核心视觉依据;
* 当autoExclusive属性为true(默认)时,设置某一按钮的checked为true,会自动取消同组其他按钮的选中状态,实现"多选一"的单选逻辑。
*
* 【关联API详解】
* 1. bool isChecked() const
* - 功能:获取单选按钮当前的选中状态
* - 返回值:bool类型;true表示已选中,false表示未选中;QRadioButton默认返回false
* - 调用示例:
* // 判断"女"单选按钮是否被选中
* bool isSelected = ui->radioBtnFemale->isChecked();
* if (isSelected) {
* qDebug() << "当前选中的性别为:女";
* }
*
* 2. void setChecked(bool checked)
* - 功能:手动设置单选按钮的选中状态
* - 参数:checked - 布尔类型,true设为选中状态,false设为未选中状态
* - 生效规则:仅当checkable=true时生效;若autoExclusive=true,设置为true会触发同组按钮的选中状态自动取消
* - 调用示例:
* // 手动选中"男"单选按钮(会自动取消同组其他按钮的选中)
* ui->radioBtnMale->setChecked(true);
* // 取消"男"单选按钮的选中状态(需手动操作,点击已选中按钮不会自动取消)
* ui->radioBtnMale->setChecked(false);
*
* 【关键注意事项】
* 1. 前置条件:必须保证checkable属性为true,否则该属性的读取和设置操作均无实际意义;
* 2. 交互特性:点击未选中的单选按钮会自动将其checked设为true,但点击已选中的单选按钮不会自动将其设为false(需通过代码实现);
* 3. 信号关联:推荐使用toggled(bool checked)信号监听选中状态变化,该信号会在checked属性改变时触发,参数直接标识当前选中状态。
*
* 【典型使用示例】
* ===================================== 基础选中状态判断与设置 =====================================
* // 1. 初始化时设置默认选中项
* ui->radioBtnMale->setChecked(true);
*
* // 2. 按钮点击事件中判断选中状态
* void Widget::on_confirmBtn_clicked() {
* if (ui->radioBtnMale->isChecked()) {
* qDebug() << "用户选择了男性";
* } else if (ui->radioBtnFemale->isChecked()) {
* qDebug() << "用户选择了女性";
* }
* }
*
* // 3. 监听选中状态变化
* connect(ui->radioBtnFemale, &QRadioButton::toggled, this, [=](bool checked) {
* if (checked) {
* qDebug() << "用户切换选中项为:女";
* }
* });
*/
QRadioButton* rb=new QRadioButton(this);
//设置选项的文本显示
rb->setText("选项");
//移动位置
rb->setGeometry(100,100,100,100);
//设置该选项为可选
rb->setCheckable(true);
//看看选项有没有被选择
qDebug() << rb->isChecked();
}
Widget::~Widget()
{
delete ui;
}
2.1.4 典型代码示例(两个实用场景,一看就懂)
示例一:基础可选中状态设置
这是最常用的场景,默认所有选项都可选中,某个选项暂时不可用:
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// QRadioButton 默认 checkable=true,无需手动设置
// 我们可以打印一下验证
qDebug() << "男单选按钮是否可选中:" << ui->radioButton_male->isCheckable();
qDebug() << "女单选按钮是否可选中:" << ui->radioButton_female->isCheckable();
// 假设"其他"选项暂时不可用,关闭它的可选中能力
ui->radioButton_other->setCheckable(false);
qDebug() << "其他单选按钮是否可选中:" << ui->radioButton_other->isCheckable();
}
Widget::~Widget()
{
delete ui;
}
示例二:动态切换可选中状态
这个场景也很常用,比如用户勾选了 "我要自定义性别",才让 "其他" 选项可选中:
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QCheckBox>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 初始状态:"其他"选项不可选中
ui->radioButton_other->setCheckable(false);
// 假设界面上有一个 QCheckBox,文本是"我要自定义性别"
// 关联复选框的状态变化信号,动态切换"其他"选项的可选中能力
connect(ui->checkBox_custom, &QCheckBox::toggled, this, [=](bool checked) {
if (checked) {
// 复选框选中,让"其他"选项可选中
ui->radioButton_other->setCheckable(true);
} else {
// 复选框取消选中,让"其他"选项不可选中,同时取消它的选中状态
ui->radioButton_other->setCheckable(false);
ui->radioButton_other->setChecked(false);
}
});
}
Widget::~Widget()
{
delete ui;
}
2.1.5 关键注意事项与新手必踩的坑(100% 避坑指南)
checkable 属性看起来简单,但新手很容易踩坑,我把最常见的几个坑列出来,每个都讲清楚 "为什么错""怎么改":
坑点一:checkable=false 时,调用 setChecked () 没反应
问题描述 :新手先把 checkable 设为 false,然后调用 setChecked(true),结果按钮根本没被选中,以为是代码写错了。
原因分析 :checkable 是 checked 属性的必要前提 ------ 如果 checkable=false,按钮根本不具备被选中的能力,checked 属性的修改操作会直接被 Qt 忽略,不会生效。
解决方式 :在调用 setChecked() 之前,必须先确保 checkable=true,或者不要关闭 checkable(QRadioButton 默认是 true,无需手动设置)。
坑点二:混淆 setCheckable (false) 和 setEnabled (false)
问题描述 :新手想禁用某个选项,不知道该用 setCheckable(false) 还是 setEnabled(false),随便用了一个,结果效果不对。
原因分析:这两个函数的效果完全不一样,我用通俗的话讲清楚它们的区别:
- setCheckable(false):只是 "不让选中",但按钮仍然可以响应点击事件(比如 clicked 信号仍然会触发),视觉上只是没有选中圆点,其他和正常按钮一样;
- setEnabled(false) :是 "彻底禁用",按钮不仅不能被选中,也不能响应任何点击、鼠标悬停事件,视觉上会变成灰色的禁用状态,用户一看就知道 "这个按钮不能用"。解决方式:根据场景选择:
- 如果只是 "暂时不让选中,但可以点击提示用户",用
setCheckable(false); - 如果是 "彻底不让用,连点击都不行",用
setEnabled(false)(这是更常用、更彻底的禁用方式)。
坑点三:QRadioButton 默认 checkable=false(其实是 true,新手记错了)
问题描述 :新手以为 QRadioButton 默认 checkable=false,每次都手动调用 setCheckable(true),其实是多余的。
原因分析 :QRadioButton 作为专门的单选按钮,默认就是 checkable=true,无需手动设置,只有 QPushButton 默认是 checkable=false(因为 QPushButton 通常不需要选中状态)。
解决方式 :QRadioButton 不用手动设置 checkable=true,只有在需要关闭可选中能力时,才调用 setCheckable(false)。
2.2 属性二:checked(是否已选中)------ 单选按钮的核心状态标识
2.2.1 属性的核心定义
checked 属性用于标识单选按钮当前是否处于 "被选中" 状态,仅在 checkable 属性为 true 时生效。
通俗理解:checked 就像 "单选题选项的选中标记"------ 如果标记为 true,这个选项前面会显示一个标志性的 "圆点"(样式可通过 QSS 修改),表示 "用户选了这个";如果标记为 false,就没有这个圆点,表示 "用户没选这个"。
当 autoExclusive 属性为 true(QRadioButton 默认值)时,设置某一按钮的 checked 为 true,会自动取消同组(同一父控件)其他按钮的选中状态,这就是 "多选一" 的核心逻辑。
2.2.2 数据类型
bool 类型,true 表示已选中,false 表示未选中。
2.2.3 关联 API 详解(逐词逐句,零模糊)
1. 获取当前选中状态:bool isChecked () const
函数原型:
bool QAbstractButton::isChecked() const;
逐词逐句底层解析:
bool:返回值类型,返回按钮当前的选中状态;QAbstractButton:::说明这是 QAbstractButton 的成员函数;isChecked():函数名,"是否已选中" 的意思;- 最后的
const:常成员函数,只读取选中状态,不修改按钮状态。
返回值说明:
- 如果按钮已被选中,返回
true; - 如果按钮未被选中,返回
false; - QRadioButton 默认返回
false(初始状态未选中)。
调用示例:
// 判断"女"单选按钮是否被选中
bool isFemaleSelected = ui->radioButton_female->isChecked();
if (isFemaleSelected) {
qDebug() << "当前选中的性别为:女";
} else {
qDebug() << "当前未选中女";
}
2. 设置选中状态:void setChecked (bool checked)
函数原型:
void QAbstractButton::setChecked(bool checked);
逐词逐句底层解析:
void:无返回值;bool checked:入参,true设为选中状态,false设为未选中状态。
参数说明:
checked:要设置的新选中状态;- 仅当
checkable=true时,这个参数才会生效; - 如果
autoExclusive=true(默认),设置为true会自动取消同组其他按钮的选中状态。
生效规则:
- 调用后立即生效,按钮界面会实时更新选中圆点;
- 如果
autoExclusive=true,设置某一按钮为true,同组其他按钮会自动变为false; - 点击已选中的 QRadioButton 不会自动取消选中(需通过代码调用
setChecked(false),或依赖autoExclusive由其他按钮触发取消)。
调用示例:
// 手动选中"男"单选按钮(会自动取消同组其他按钮的选中)
ui->radioButton_male->setChecked(true);
// 手动取消"男"单选按钮的选中状态(需手动操作,点击已选中按钮不会自动取消)
ui->radioButton_male->setChecked(false);
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们就来学习QRadioButton的checkable属性和checked属性
//这两个属性也是很简单,checkable属性就是控制该选项能不能被选择,而checked属性就是看该选项有没有被选择罢了
//是很简单的
/**
* @property QRadioButton::checkable
* @brief QRadioButton的可选中能力控制属性(继承自QAbstractButton)
* @details 该属性用于控制单选按钮是否具备"被选中/取消选中"的交互能力,是checked属性生效的核心前置条件;
* 若该属性为false,单选按钮仅能作为普通文本按钮显示,无法通过点击或代码修改选中状态(checked属性始终为false);
* 若该属性为true,单选按钮可响应点击操作切换选中状态,也可通过代码手动设置checked属性,是实现单选交互的基础。
* QRadioButton默认将该属性设为true,无需手动配置即可满足常规单选场景需求。
*
* 【关联API详解】
* 1. bool isCheckable() const
* - 功能:获取单选按钮当前的可选中能力状态
* - 返回值:bool类型;true表示具备可选中能力,false表示无选中能力;QRadioButton默认返回true
* - 调用示例:
* // 读取"男"单选按钮的可选中状态
* bool canCheck = ui->radioBtnMale->isCheckable();
*
* 2. void setCheckable(bool enable)
* - 功能:开启或关闭单选按钮的可选中能力
* - 参数:enable - 布尔类型,true为开启可选中能力,false为关闭
* - 生效规则:调用后立即生效,关闭可选中能力后,checked属性的修改操作将失效
* - 调用示例:
* // 关闭可选中能力,按钮变为不可选状态
* ui->radioBtnMale->setCheckable(false);
* // 恢复可选中能力(默认状态)
* ui->radioBtnMale->setCheckable(true);
*
* 【关键注意事项】
* 1. 前置依赖:该属性是checked属性生效的必要条件,若checkable=false,调用setChecked()修改选中状态不会产生任何效果;
* 2. 默认状态:QRadioButton初始化时默认开启可选中能力(checkable=true),仅在需将单选按钮作为"纯展示文本"时才需关闭;
* 3. 交互表现:关闭可选中能力后,单选按钮的点击操作不会触发toggled()信号,也不会改变界面显示样式。
*
* ---
*
* @property QRadioButton::checked
* @brief QRadioButton的选中状态标识属性(继承自QAbstractButton)
* @details 该属性用于标识单选按钮当前是否处于"被选中"状态,仅在checkable属性为true时生效;
* 选中状态的QRadioButton会在界面上显示标志性的圆点指示器,未选中状态则无该标识,是用户区分选中项的核心视觉依据;
* 当autoExclusive属性为true(默认)时,设置某一按钮的checked为true,会自动取消同组其他按钮的选中状态,实现"多选一"的单选逻辑。
*
* 【关联API详解】
* 1. bool isChecked() const
* - 功能:获取单选按钮当前的选中状态
* - 返回值:bool类型;true表示已选中,false表示未选中;QRadioButton默认返回false
* - 调用示例:
* // 判断"女"单选按钮是否被选中
* bool isSelected = ui->radioBtnFemale->isChecked();
* if (isSelected) {
* qDebug() << "当前选中的性别为:女";
* }
*
* 2. void setChecked(bool checked)
* - 功能:手动设置单选按钮的选中状态
* - 参数:checked - 布尔类型,true设为选中状态,false设为未选中状态
* - 生效规则:仅当checkable=true时生效;若autoExclusive=true,设置为true会触发同组按钮的选中状态自动取消
* - 调用示例:
* // 手动选中"男"单选按钮(会自动取消同组其他按钮的选中)
* ui->radioBtnMale->setChecked(true);
* // 取消"男"单选按钮的选中状态(需手动操作,点击已选中按钮不会自动取消)
* ui->radioBtnMale->setChecked(false);
*
* 【关键注意事项】
* 1. 前置条件:必须保证checkable属性为true,否则该属性的读取和设置操作均无实际意义;
* 2. 交互特性:点击未选中的单选按钮会自动将其checked设为true,但点击已选中的单选按钮不会自动将其设为false(需通过代码实现);
* 3. 信号关联:推荐使用toggled(bool checked)信号监听选中状态变化,该信号会在checked属性改变时触发,参数直接标识当前选中状态。
*
* 【典型使用示例】
* ===================================== 基础选中状态判断与设置 =====================================
* // 1. 初始化时设置默认选中项
* ui->radioBtnMale->setChecked(true);
*
* // 2. 按钮点击事件中判断选中状态
* void Widget::on_confirmBtn_clicked() {
* if (ui->radioBtnMale->isChecked()) {
* qDebug() << "用户选择了男性";
* } else if (ui->radioBtnFemale->isChecked()) {
* qDebug() << "用户选择了女性";
* }
* }
*
* // 3. 监听选中状态变化
* connect(ui->radioBtnFemale, &QRadioButton::toggled, this, [=](bool checked) {
* if (checked) {
* qDebug() << "用户切换选中项为:女";
* }
* });
*/
QRadioButton* rb=new QRadioButton(this);
//设置选项的文本显示
rb->setText("选项");
//移动位置
rb->setGeometry(100,100,100,100);
//设置该选项为可选
rb->setCheckable(true);
//看看选项有没有被选择
qDebug() << rb->isChecked();
}
Widget::~Widget()
{
delete ui;
}
2.2.4 典型代码示例(三个实用场景,一看就懂)
示例一:初始化时设置默认选中项
这是最常用的场景,程序启动时默认选中某个选项,比如性别选择默认选中 "男":
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 初始化时默认选中"男"单选按钮
ui->radioButton_male->setChecked(true);
// 同时更新标签的提示文字
ui->label->setText("你选择的性别为:男");
}
Widget::~Widget()
{
delete ui;
}
示例二:点击确认按钮时判断选中项
这个场景也非常常用,用户选好后,点击 "确认" 按钮,程序判断用户选了哪个:
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 关联"确认"按钮的点击信号
connect(ui->pushButton_confirm, &QPushButton::clicked, this, [=]() {
// 判断用户选了哪个
if (ui->radioButton_male->isChecked()) {
qDebug() << "用户选择了:男";
ui->label->setText("你选择的性别为:男");
} else if (ui->radioButton_female->isChecked()) {
qDebug() << "用户选择了:女";
ui->label->setText("你选择的性别为:女");
} else if (ui->radioButton_other->isChecked()) {
qDebug() << "用户选择了:其他";
ui->label->setText("你选择的性别为:其他");
} else {
qDebug() << "用户还没有选择任何选项";
ui->label->setText("请先选择性别");
}
});
}
Widget::~Widget()
{
delete ui;
}
示例三:动态切换选中状态
这个场景适合 "上一题 / 下一题" 的单选题界面,点击 "下一题" 时自动选中下一个选项:
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, currentIndex(0) // 初始选中索引为 0
{
ui->setupUi(this);
// 把单选按钮放到一个列表里,方便管理
QList<QRadioButton*> radioList;
radioList << ui->radioButton_male << ui->radioButton_female << ui->radioButton_other;
// 初始选中第一个
radioList[currentIndex]->setChecked(true);
// 关联"下一个"按钮的点击信号
connect(ui->pushButton_next, &QPushButton::clicked, this, [=]() mutable {
// 取消当前选中
radioList[currentIndex]->setChecked(false);
// 索引加 1,超过列表长度则回到 0
currentIndex = (currentIndex + 1) % radioList.size();
// 选中下一个
radioList[currentIndex]->setChecked(true);
});
}
Widget::~Widget()
{
delete ui;
}
2.2.5 关键注意事项与新手必踩的坑(100% 避坑指南)
坑点一:checkable=false 时,调用 setChecked () 没反应
这个坑和 checkable 属性的坑点一一样,我再强调一遍:checkable 是 checked 的前提 ,必须先确保 checkable=true,setChecked() 才会生效。
坑点二:点击已选中的 QRadioButton,它会自动取消选中(其实不会)
问题描述:新手以为点击已选中的 QRadioButton,它会自动取消选中,结果点了好几次,它还是选中状态,以为是 bug。
原因分析:这是正常的!QRadioButton 的设计逻辑是 "单选"------ 同一组里必须有且仅有一个选中(如果都没设置默认选中,初始可以都不选),所以点击已选中的按钮,Qt 不会让它取消选中,否则同一组就没有选中项了,不符合单选的逻辑。
解决方式 :如果确实需要取消选中(比如特殊场景),只能通过代码调用 setChecked(false),或者点击同组的其他按钮,让其他按钮选中,从而取消当前按钮的选中。
坑点三:不知道怎么判断用户选了哪个,只能一个个写 if
问题描述 :新手判断用户选了哪个选项时,只能用 if (isChecked()) 一个个判断,选项多了代码非常冗长。
解决方式:有两种更简洁的方法:
- 用 QButtonGroup:我们后面会专门讲 QButtonGroup,它可以直接获取当前选中的按钮,不用一个个判断;
- 用 QList 存储按钮 :像示例三那样,把所有单选按钮放到一个 QList 里,遍历列表判断哪个是选中的,或者用信号的
sender()方法判断是哪个按钮触发的。
2.3 属性三:autoExclusive(是否排他)------ 实现 "单选" 的核心属性
2.3.1 属性的核心定义
autoExclusive 属性用于控制同一父控件下的多个 QRadioButton 是否具备 "互斥选中" 特性,是实现 "多选一" 单选逻辑的核心属性。
通俗理解:autoExclusive 就像 "单选题的规则"------ 如果规则开启(autoExclusive=true),同一道题(同一父控件)里,你选了 A,就会自动取消 B、C、D 的选中,保证同一题里只有一个选中;如果规则关闭(autoExclusive=false),这道题就变成了 "多选题",你可以同时选 A、B、C、D,失去了单选的特性。
QRadioButton 作为专门的单选按钮,默认将 autoExclusive 设为 true,无需手动配置即可满足常规的单选场景需求。
2.3.2 数据类型
bool 类型,true 表示开启排他性(单选),false 表示关闭排他性(允许多选)。
2.3.3 关键概念:什么是 "同组"?
在讲 API 之前,我们必须先搞懂一个非常重要的概念 ------"同组" 的定义 ,这是理解 autoExclusive 作用范围的关键:
"同组" 指的是 "同一父控件下的所有 QRadioButton"。
通俗理解:父控件就像 "单选题的题号"------ 同一题号(同一父控件)下的选项是一组,组内互斥;不同题号(不同父控件)下的选项是不同的组,组间互不影响。
比如:
- 我们把 "男""女""其他" 三个单选按钮都放在同一个 QWidget(当前窗口)里,它们就是同一组,组内互斥;
- 如果我们把 "男""女" 放在一个 QGroupBox(分组框)里,把 "本科""硕士""博士" 放在另一个 QGroupBox 里,那么这两个 QGroupBox 就是不同的父控件,"性别组" 和 "学历组" 是两个独立的组,组内互斥,组间互不影响 ------ 你选了 "男",不会影响 "本科" 的选中状态。
这个 "同组" 的定义非常重要,后面讲 QButtonGroup 时也会用到。
2.3.4 关联 API 详解(逐词逐句,零模糊)
1. 获取当前排他性状态:bool autoExclusive () const
函数原型:
bool QAbstractButton::autoExclusive() const;
逐词逐句底层解析:
bool:返回值类型,返回按钮当前的排他性状态;QAbstractButton:::说明这是 QAbstractButton 的成员函数;autoExclusive():函数名,"是否排他" 的意思;- 最后的
const:常成员函数,只读取排他性状态,不修改按钮状态。
返回值说明:
- 如果按钮开启了排他性,返回
true; - 如果按钮关闭了排他性,返回
false; - QRadioButton 默认返回
true。
调用示例:
// 获取"男"单选按钮的排他性状态
bool isExclusive = ui->radioButton_male->autoExclusive();
qDebug() << "男单选按钮是否排他:" << isExclusive;
2. 设置排他性状态:void setAutoExclusive (bool enable)
函数原型:
void QAbstractButton::setAutoExclusive(bool enable);
逐词逐句底层解析:
void:无返回值;bool enable:入参,true开启排他性,false关闭排他性。
参数说明:
enable:要设置的新排他性状态;- 若为某一个按钮设置该属性,同组所有按钮的排他性会同步变更(组内属性统一)------ 因为排他性是 "组" 的特性,不是单个按钮的特性;
- 关闭排他性后,多个按钮可被同时选中(失去单选特性,行为接近 QCheckBox 复选框)。
生效规则:
- 调用后立即生效,排他性作用范围为 "同一父控件下的所有 QRadioButton";
- 开启排他性后,选中其中一个按钮,会自动取消同组其他按钮的选中状态。
调用示例:
// 开启排他性(QRadioButton 默认状态,无需手动设置)
ui->radioButton_male->setAutoExclusive(true);
// 关闭排他性,允许同组多个单选按钮被同时选中(失去单选特性)
ui->radioButton_male->setAutoExclusive(false);
ui->radioButton_female->setAutoExclusive(false);
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们来学习QRadioButton的一个重要属性,那就是autoExclusive属性
//这个属性的作用就是,单设置了这个选项的autoExclusive属性为true之后
//那么其他的选项就都会被取消选中,所有选项都是哦,只有被选中的那个选项不会
//这就是单选嘛~~~
//需要注意的是对于每个QRadioButton 来说默认就是排他的,即我们不设置,它就是true
//即在同一个界面下,多个QRadioButton只要有一个被选择,那么其他的有被选择的就会被取消选择
//我们要是想不同的不要这样子,就需要对QRadioButton进行分组,这个下个文件会解析
/**
* @property QRadioButton::autoExclusive
* @brief QRadioButton的排他性控制属性(继承自QAbstractButton)
* @details 该属性用于控制同一父控件下的多个QRadioButton是否具备"互斥选中"特性,核心逻辑为:
* 当该属性为true时,选中其中一个QRadioButton,会自动取消同组(同一父控件)其他QRadioButton的选中状态,实现"多选一"的单选核心逻辑;
* 当该属性为false时,取消互斥特性,多个QRadioButton可被同时选中(此时行为接近QCheckBox复选框,失去单选按钮的本质特性);
* QRadioButton默认将该属性设为true,无需手动配置即可满足常规的单选场景需求。
*
* 【关联API详解】
* 1. bool autoExclusive() const
* - 功能:获取单选按钮当前的排他性状态
* - 返回值:bool类型;true表示开启排他性(默认),false表示关闭排他性
* - 调用示例:
* // 读取"男"单选按钮的排他性状态
* bool isExclusive = ui->radioBtnMale->autoExclusive();
*
* 2. void setAutoExclusive(bool enable)
* - 功能:开启或关闭单选按钮的排他性
* - 参数:enable - 布尔类型,true为开启排他性,false为关闭
* - 生效规则:调用后立即生效,排他性作用范围为"同一父控件下的所有QRadioButton";
* 若为某一个按钮设置该属性,同组所有按钮的排他性会同步变更(组内属性统一)。
* - 调用示例:
* // 关闭排他性,允许同组多个单选按钮被同时选中
* ui->radioBtnMale->setAutoExclusive(false);
* // 恢复默认排他性(开启)
* ui->radioBtnMale->setAutoExclusive(true);
*
* 【关键注意事项】
* 1. "同组"定义:排他性仅作用于**同一父控件**(如QWidget、QGroupBox、QVBoxLayout所属的父容器)下的QRadioButton;
* 不同父控件的QRadioButton互不影响,即使都开启排他性,也不会互相取消选中状态。
* 2. 默认行为:QRadioButton初始化时默认开启排他性(autoExclusive=true),这是其作为"单选按钮"的核心特性,无需手动设置;
* 仅在特殊场景(如需要单选按钮具备复选框行为)时才需关闭。
* 3. 分组实现:若需在同一界面实现多组独立的单选逻辑(如"性别"和"学历"两组单选),需将不同组的QRadioButton放入不同的父控件(如QGroupBox),
* 利用父控件隔离排他性作用范围,保证组内互斥、组间独立。
* 4. 优先级:该属性仅影响"选中时取消其他按钮"的行为,不影响checkable/checked属性的基础功能;
* 即使关闭排他性,checkable=true仍是checked属性生效的前提。
*
* 【典型使用示例】
* ===================================== 示例1:默认排他性(单组单选) =====================================
* // 两个单选按钮共用同一父控件(当前窗口),默认开启排他性,实现"多选一"
* QRadioButton* radioMale = new QRadioButton("男", this);
* QRadioButton* radioFemale = new QRadioButton("女", this);
* // 选中"男",会自动取消"女"的选中状态(无需额外代码)
* radioMale->setChecked(true);
*
* ===================================== 示例2:分组实现多组独立单选 =====================================
* // 需求:实现"性别"和"学历"两组互不影响的单选逻辑
* // 步骤1:创建两个分组容器(QGroupBox)
* QGroupBox* genderGroup = new QGroupBox("性别", this);
* QGroupBox* eduGroup = new QGroupBox("学历", this);
*
* // 步骤2:将不同组的单选按钮放入对应容器
* QRadioButton* radioMale = new QRadioButton("男", genderGroup);
* QRadioButton* radioFemale = new QRadioButton("女", genderGroup);
* QRadioButton* radioUndergrad = new QRadioButton("本科", eduGroup);
* QRadioButton* radioMaster = new QRadioButton("硕士", eduGroup);
*
* // 效果:genderGroup内的按钮互斥,eduGroup内的按钮互斥,两组选中状态互不影响
*
* ===================================== 示例3:关闭排他性(模拟复选框) =====================================
* // 关闭排他性,允许同组多个单选按钮被同时选中
* QRadioButton* radioOpt1 = new QRadioButton("选项1", this);
* QRadioButton* radioOpt2 = new QRadioButton("选项2", this);
* radioOpt1->setAutoExclusive(false);
* radioOpt2->setAutoExclusive(false);
*
* // 可同时选中两个按钮(失去单选特性)
* radioOpt1->setChecked(true);
* radioOpt2->setChecked(true);
*/
//我们这里直接使用ui吧嘿嘿~~
//我们设置了三个按钮,为男女其他
this->ui->radioButton_male->setAutoExclusive(true);
this->ui->radioButton_female->setAutoExclusive(true);
this->ui->radioButton_other->setAutoExclusive(true);
}
Widget::~Widget()
{
delete ui;
}
2.3.5 典型代码示例(三个实用场景,一看就懂)
示例一:默认排他性(单组单选)
这是最常用的场景,同一父控件下的多个单选按钮,默认开启排他性,实现 "多选一":
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 三个单选按钮的父控件都是当前窗口(this),属于同一组
// QRadioButton 默认 autoExclusive=true,无需手动设置
// 选中"男",会自动取消"女"和"其他"的选中状态
ui->radioButton_male->setChecked(true);
ui->label->setText("你选择的性别为:男");
}
Widget::~Widget()
{
delete ui;
}
示例二:用 QGroupBox 实现多组独立单选
这个场景非常经典,比如同时选 "性别" 和 "学历",两组互不影响:
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QGroupBox>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 步骤1:创建两个 QGroupBox 作为分组容器(不同的父控件)
QGroupBox *genderGroup = new QGroupBox("性别", this);
genderGroup->setGeometry(50, 50, 200, 120);
QGroupBox *eduGroup = new QGroupBox("学历", this);
eduGroup->setGeometry(50, 190, 200, 150);
// 步骤2:创建性别组的单选按钮,父控件是 genderGroup
QRadioButton *radioMale = new QRadioButton("男", genderGroup);
QRadioButton *radioFemale = new QRadioButton("女", genderGroup);
radioMale->move(20, 30);
radioFemale->move(20, 60);
radioMale->setChecked(true); // 默认选中男
// 步骤3:创建学历组的单选按钮,父控件是 eduGroup
QRadioButton *radioUndergrad = new QRadioButton("本科", eduGroup);
QRadioButton *radioMaster = new QRadioButton("硕士", eduGroup);
QRadioButton *radioDoctor = new QRadioButton("博士", eduGroup);
radioUndergrad->move(20, 30);
radioMaster->move(20, 60);
radioDoctor->move(20, 90);
radioUndergrad->setChecked(true); // 默认选中本科
// 效果:genderGroup 内的按钮互斥,eduGroup 内的按钮互斥,两组选中状态互不影响
// 你选了"女",不会影响"本科"的选中状态
}
Widget::~Widget()
{
delete ui;
}
示例三:关闭排他性(模拟复选框)
这个场景比较特殊,关闭排他性,让 QRadioButton 可以同时选中多个(失去单选特性):
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 关闭所有单选按钮的排他性
ui->radioButton_male->setAutoExclusive(false);
ui->radioButton_female->setAutoExclusive(false);
ui->radioButton_other->setAutoExclusive(false);
// 现在可以同时选中多个按钮了(失去单选特性,行为接近 QCheckBox)
ui->radioButton_male->setChecked(true);
ui->radioButton_female->setChecked(true);
}
Widget::~Widget()
{
delete ui;
}
2.3.6 关键注意事项与新手必踩的坑(100% 避坑指南)
坑点一:同一界面下的所有 QRadioButton 都互斥(因为父控件相同)
问题描述:新手在界面上拖了 "性别" 和 "学历" 两组单选按钮,结果选了 "男","本科" 就取消选中了,两组互相影响,以为是 bug。
原因分析:因为这两组单选按钮的父控件都是同一个 QWidget(当前窗口),属于同一组,所以会互斥。
解决方式:用不同的父控件把它们分开 ------ 比如用 QGroupBox、QWidget、QVBoxLayout 等作为分组容器,把不同组的单选按钮放到不同的容器里,这样它们的父控件不同,就属于不同的组,组间互不影响了(就像示例二那样);或者用我们后面要讲的 QButtonGroup 来分组,更灵活。
坑点二:只给一个按钮设置 setAutoExclusive (false),其他按钮没设置,结果还是互斥
问题描述 :新手只给 "男" 按钮设置了 setAutoExclusive(false),其他按钮没设置,结果还是只能选一个,以为没生效。
原因分析 :排他性是 "组" 的特性,不是单个按钮的特性 ------ 只要同组里有一个按钮的 autoExclusive=true,整个组就是排他的;只有同组所有按钮的 autoExclusive=false,才会关闭排他性。
解决方式 :如果要关闭排他性,必须给同组所有按钮都设置 setAutoExclusive(false)。
坑点三:QPushButton 也有 autoExclusive 属性,默认也是 true(其实是 false)
问题描述 :新手以为 QPushButton 的 autoExclusive 默认也是 true,结果拖了几个 QPushButton,设置了 checkable=true,发现它们不互斥。
原因分析 :QPushButton 默认 autoExclusive=false,因为 QPushButton 通常不需要单选特性;只有 QRadioButton 默认 autoExclusive=true。
解决方式 :如果需要 QPushButton 也互斥,可以手动给它们设置 setAutoExclusive(true),或者用 QButtonGroup 分组。

第三章 QRadioButton 核心信号深度解析(clicked/pressed/released/toggled)
讲完了核心属性,我们再讲 QRadioButton 的四个核心交互信号 ------clicked、pressed、released、toggled。这四个信号的触发时机、关联逻辑、适用场景差异显著,很多新手搞不清该用哪个,这一章我会用最通俗的语言,把每个信号讲透,最后明确告诉你为什么 toggled 是适配 QRadioButton 选中状态监听的最优选择。
3.1 前置基础说明
在讲具体信号之前,我们先回顾一下 QRadioButton 的默认特性,以下所有信号解析均基于该默认特性:
checkable=true:具备被选中的能力(是checked属性生效的前提);autoExclusive=true:同组内选中一个按钮,会自动取消其他按钮的选中状态。
3.2 信号一:clicked(完成一次完整的鼠标点击)
3.2.1 通俗定义
clicked 表示 "完成一次完整的鼠标点击操作"------ 就像按电梯按钮,必须 "按下按钮→松开手指" 这个完整动作完成,才会触发电梯响应,少一步都不行。
3.2.2 触发时机
只有当鼠标左键按下 QRadioButton,且在按钮范围内释放鼠标时,才会触发该信号:
- 若按下按钮后,将鼠标拖动到按钮外再释放,不会触发
clicked; - 若仅按下鼠标不释放,也不会触发
clicked。
3.2.3 关键特性
- 仅响应 "按下 + 释放" 的完整动作,与按钮的选中状态无关;
- 即使点击的是已选中的 QRadioButton (点击后选中状态无变化),只要完成 "按下 + 释放",仍会触发
clicked。
3.2.4 适用场景
仅需响应 "用户完成一次点击动作" 的通用场景,不关注按钮是否真的选中 / 取消选中。
3.2.5 代码示例
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 关联"男"单选按钮的 clicked 信号
connect(ui->radioButton_male, &QRadioButton::clicked, this, [=]() {
qDebug() << "clicked 信号触发:用户完成了一次点击动作";
// 注意:这里无法知道按钮是否真的被选中,因为点击已选中的按钮也会触发
});
}
Widget::~Widget()
{
delete ui;
}
3.3 信号二:pressed(鼠标左键按下的瞬间)
3.3.1 通俗定义
pressed 表示 "鼠标左键按下按钮的瞬间"------ 就像按门铃,手指刚碰到门铃按钮(按下瞬间),门铃就响了,无需松开手指。
3.3.2 触发时机
只要鼠标左键按下 QRadioButton(无论是否释放、无论释放位置在哪),按下的瞬间立即触发:
- 按下后即使不释放鼠标,也会触发
pressed; - 按下后拖动鼠标到按钮外再释放,依然会触发
pressed(仅在按下时触发)。
3.3.3 关键特性
- 仅响应 "按下" 这个单一动作,与释放动作、按钮选中状态均无关;
- 触发时机早于
clicked和released。
3.3.4 适用场景
需要 "按下按钮即时反馈" 的场景(如按下时按钮变色、播放按键音效)。
3.3.5 代码示例
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 关联"男"单选按钮的 pressed 信号
connect(ui->radioButton_male, &QRadioButton::pressed, this, [=]() {
qDebug() << "pressed 信号触发:鼠标按下了按钮";
// 可以在这里做即时反馈,比如让按钮变色
ui->radioButton_male->setStyleSheet("color: red;");
});
}
Widget::~Widget()
{
delete ui;
}
3.4 信号三:released(鼠标左键从按钮上释放的瞬间)
3.4.1 通俗定义
released 表示 "鼠标左键从按钮上释放的瞬间"------ 就像拧水龙头,先按下开关(pressed),松开开关的瞬间(released)水流停止,释放动作是核心。
3.4.2 触发时机
只要鼠标左键先按下 QRadioButton,之后无论在按钮内 / 外释放,释放的瞬间都会触发:
- 仅释放鼠标(未按下过按钮),不会触发
released; - 若按下按钮后在按钮外释放,会触发
released,但不会触发clicked。
3.4.3 关键特性
- 仅响应 "释放" 这个单一动作,需先有 "按下" 动作作为前提,与按钮选中状态无关;
- 若按下按钮后在按钮外释放,会触发
released,但不会触发clicked。
3.4.4 适用场景
需要 "释放按钮即时反馈" 的场景(如释放时停止加载动画、取消临时选中状态)。
3.4.5 代码示例
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 关联"男"单选按钮的 released 信号
connect(ui->radioButton_male, &QRadioButton::released, this, [=]() {
qDebug() << "released 信号触发:鼠标释放了按钮";
// 可以在这里恢复按钮的颜色
ui->radioButton_male->setStyleSheet("");
});
}
Widget::~Widget()
{
delete ui;
}
3.5 信号四:toggled(选中状态发生变化的瞬间)------ QRadioButton 的首选信号
3.5.1 通俗定义
toggled 表示 "按钮的选中状态(checked 属性)发生变化的瞬间"------ 就像电灯开关,只有开关从 "关" 变 "开"、或从 "开" 变 "关" 时,才会触发灯的亮 / 灭,单纯用手按住开关(不拨动),灯不会有任何变化。
3.5.2 触发时机
只有当 QRadioButton 的 checked 属性从 "未选中(false)" 变为 "选中(true)",或 ** 从 "选中(true)" 变为 "未选中(false)"** 时,才会触发该信号:
- 点击未选中的 QRadioButton:该按钮
checked变为true,触发toggled(true);同时同组其他已选中的按钮checked变为false,触发toggled(false); - 点击已选中的 QRadioButton:选中状态无变化,不会触发
toggled; - 代码手动设置
setChecked(true/false):选中状态变化,也会触发toggled。
3.5.3 关键特性
- 仅响应 "选中状态变化",与鼠标动作(按下 / 释放)无关;
- 信号携带 bool 类型参数
checked,直接标识按钮当前的选中状态(true= 选中,false= 取消选中); - 是唯一能精准反映 QRadioButton 核心交互(选中 / 取消选中)的信号。
3.5.4 适用场景
所有需要监听 QRadioButton 选中状态变化的场景(如性别选择、模式切换后的逻辑处理)。
3.5.5 代码示例
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QLabel>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 关联"男"单选按钮的 toggled 信号
connect(ui->radioButton_male, &QRadioButton::toggled, this, [=](bool checked) {
if (checked) {
qDebug() << "toggled 信号触发:男单选按钮被选中了";
ui->label->setText("你选择的性别为:男");
} else {
qDebug() << "toggled 信号触发:男单选按钮被取消选中了";
}
});
// 关联"女"单选按钮的 toggled 信号
connect(ui->radioButton_female, &QRadioButton::toggled, this, [=](bool checked) {
if (checked) {
qDebug() << "toggled 信号触发:女单选按钮被选中了";
ui->label->setText("你选择的性别为:女");
}
});
}
Widget::~Widget()
{
delete ui;
}
3.6 四类信号核心区别对比(通俗版,一目了然)
为了让你更清楚地看到四个信号的区别,我做了一个对比表格,用最通俗的语言总结:
表格
| 信号名称 | 触发核心 | 是否依赖鼠标完整动作 | 是否关联选中状态 | 能否知道当前是否选中 |
|---|---|---|---|---|
| clicked | 完成按下 + 释放 | 是 | 否 | 否 |
| pressed | 仅鼠标按下 | 否 | 否 | 否 |
| released | 仅鼠标释放 | 否 | 否 | 否 |
| toggled | 选中状态变化 | 否 | 是 | 是(通过 checked 参数) |
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们来学习QRadioButton的选中信号的解析
//就是当用户选择QRadioButton之后,我们要使用哪个信号进行判断用户选择~~~
//那么其实就是要使用togged选项,因为QRadioButton是单选框~
//• clicked 是一次鼠标按下+鼠标释放触发的.
//• pressed 是鼠标按下触发的.
//• released 是鼠标释放触发的.
//• toggled 是 checked 属性改变时触发的.
//总的来说, toggled 是最适合 QRadioButton 的,因为是单选框,所以我们不能根据鼠标的行为来进行判断用户是不是最后选择了这一个
//而是得是toggled信号来进行判断用户是不是选择了这一个,这个最精准~~~
//如点击已选中的按钮,这三个信号仍会触发,但选中状态无变化
/**
* @brief QRadioButton核心信号(clicked/pressed/released/toggled)深度解析
* @details QRadioButton继承自QAbstractButton,具备clicked、pressed、released、toggled四类核心交互信号;
* 四类信号的触发时机、关联逻辑、适用场景差异显著,本注释通过通俗化解析,明确各信号的核心区别,
* 并说明为何toggled是适配QRadioButton选中状态监听的最优选择。
*
* 【前置基础说明】
* QRadioButton默认特性:
* 1. checkable=true:具备被选中的能力(是checked属性生效的前提);
* 2. autoExclusive=true:同组内选中一个按钮,会自动取消其他按钮的选中状态;
* 以下所有信号解析均基于该默认特性。
*
* ===================================== 信号1:clicked =====================================
* • 通俗定义:表示"完成一次完整的鼠标点击操作";
* • 触发时机:只有当鼠标左键按下QRadioButton,且在按钮范围内释放鼠标时,才会触发该信号;
* → 若按下按钮后,将鼠标拖动到按钮外再释放,不会触发clicked;
* → 若仅按下鼠标不释放,也不会触发clicked;
* • 关键特性:
* 1. 仅响应"按下+释放"的完整动作,与按钮的选中状态无关;
* 2. 即使点击的是已选中的QRadioButton(点击后选中状态无变化),只要完成"按下+释放",仍会触发clicked;
* • 通俗举例:如同按电梯按钮,必须"按下按钮→松开手指"这个完整动作完成,才会触发电梯响应,少一步都不行;
* • 适用场景:仅需响应"用户完成一次点击动作"的通用场景,不关注按钮是否真的选中/取消选中。
*
* ===================================== 信号2:pressed =====================================
* • 通俗定义:表示"鼠标左键按下按钮的瞬间";
* • 触发时机:只要鼠标左键按下QRadioButton(无论是否释放、无论释放位置在哪),按下的瞬间立即触发;
* → 按下后即使不释放鼠标,也会触发pressed;
* → 按下后拖动鼠标到按钮外再释放,依然会触发pressed(仅在按下时触发);
* • 关键特性:
* 1. 仅响应"按下"这个单一动作,与释放动作、按钮选中状态均无关;
* 2. 触发时机早于clicked和released;
* • 通俗举例:如同按门铃,手指刚碰到门铃按钮(按下瞬间),门铃就响了,无需松开手指;
* • 适用场景:需要"按下按钮即时反馈"的场景(如按下时按钮变色、播放按键音效)。
*
* ===================================== 信号3:released =====================================
* • 通俗定义:表示"鼠标左键从按钮上释放的瞬间";
* • 触发时机:只要鼠标左键先按下QRadioButton,之后无论在按钮内/外释放,释放的瞬间都会触发;
* → 仅释放鼠标(未按下过按钮),不会触发released;
* • 关键特性:
* 1. 仅响应"释放"这个单一动作,需先有"按下"动作作为前提,与按钮选中状态无关;
* 2. 若按下按钮后在按钮外释放,会触发released,但不会触发clicked;
* • 通俗举例:如同拧水龙头,先按下开关(pressed),松开开关的瞬间(released)水流停止,释放动作是核心;
* • 适用场景:需要"释放按钮即时反馈"的场景(如释放时停止加载动画、取消临时选中状态)。
*
* ===================================== 信号4:toggled =====================================
* • 通俗定义:表示"按钮的选中状态(checked属性)发生变化的瞬间";
* • 触发时机:只有当QRadioButton的checked属性从"未选中(false)"变为"选中(true)",
* 或从"选中(true)"变为"未选中(false)"时,才会触发该信号;
* → 点击未选中的QRadioButton:该按钮checked变为true,触发toggled(true);
* 同时同组其他已选中的按钮checked变为false,触发toggled(false);
* → 点击已选中的QRadioButton:选中状态无变化,不会触发toggled;
* → 代码手动设置setChecked(true/false):选中状态变化,也会触发toggled;
* • 关键特性:
* 1. 仅响应"选中状态变化",与鼠标动作(按下/释放)无关;
* 2. 信号携带bool类型参数checked,直接标识按钮当前的选中状态(true=选中,false=取消选中);
* 3. 是唯一能精准反映QRadioButton核心交互(选中/取消选中)的信号;
* • 通俗举例:如同电灯开关,只有开关从"关"变"开"、或从"开"变"关"时,才会触发灯的亮/灭,
* 单纯用手按住开关(不拨动),灯不会有任何变化;
* • 适用场景:所有需要监听QRadioButton选中状态变化的场景(如性别选择、模式切换后的逻辑处理)。
*
* 【四类信号核心区别对比(通俗版)】
* | 信号名称 | 触发核心 | 是否依赖鼠标完整动作 | 是否关联选中状态 | 能否知道当前是否选中 |
* |------------|-------------------------|----------------------|------------------|----------------------|
* | clicked | 完成按下+释放 | 是 | 否 | 否 |
* | pressed | 仅鼠标按下 | 否 | 否 | 否 |
* | released | 仅鼠标释放 | 否 | 否 | 否 |
* | toggled | 选中状态变化 | 否 | 是 | 是(通过checked参数)|
*
* 【关键结论:QRadioButton的最优信号选择】
* 1. toggled是QRadioButton的首选信号:
* - QRadioButton的核心交互是"多选一"的选中状态切换,toggled信号直接绑定选中状态变化,能精准捕获用户的选择结果;
* - 而clicked/pressed/released仅关注鼠标动作,无法判断按钮是否真的被选中(如点击已选中的按钮,这三个信号仍会触发,但选中状态无变化);
* 2. 补充说明:
* - 若需实现"按下按钮即时反馈"(如按钮变色),可搭配pressed/released;
* - 若仅需"用户点一下就执行操作"且不关注选中状态,可使用clicked;
* - 所有涉及"根据选中项执行逻辑"的场景,必须使用toggled。
*/
//就是这么简单~~~,我们知道就行
}
Widget::~Widget()
{
delete ui;
}
3.7 关键结论:QRadioButton 的最优信号选择
看完了四个信号的解析,相信你已经有答案了 ------toggled 是 QRadioButton 的首选信号,原因有两个:
- QRadioButton 的核心交互是 "多选一" 的选中状态切换 :toggled 信号直接绑定选中状态变化,能精准捕获用户的选择结果,还能通过
checked参数直接知道当前是否选中; - 其他三个信号仅关注鼠标动作:clicked/pressed/released 无法判断按钮是否真的被选中(比如点击已选中的按钮,这三个信号仍会触发,但选中状态无变化),不适合用来监听单选逻辑。
当然,如果你需要实现 "按下按钮即时反馈"(比如按钮变色),可以搭配 pressed/released;如果仅需 "用户点一下就执行操作" 且不关注选中状态,可以使用 clicked。但所有涉及 "根据选中项执行逻辑" 的场景,必须使用 toggled。
第四章 QButtonGroup 详解(灵活分组的神器)
前面我们讲了,要实现多组独立的单选,可以用不同的父控件(比如 QGroupBox)来分组,但这种方式有个缺点 ------ 必须修改界面的布局结构,把按钮放到不同的容器里。如果我们不想修改布局,或者需要更灵活的分组方式(比如给每个按钮设置一个 ID,方便获取选中项),Qt 专门为我们提供了一个类 ------QButtonGroup。
4.1 QButtonGroup 的核心作用
QButtonGroup 是一个不可见的辅助类(它不会显示在界面上),专门用来对按钮(QAbstractButton 的子类,包括 QRadioButton、QPushButton、QCheckBox)进行分组管理,它的核心作用有两个:
- 实现组内互斥:让同一 QButtonGroup 里的 QRadioButton 互斥选中,组间独立,不受父控件限制;
- 方便管理选中项 :可以直接获取当前选中的按钮,或者给按钮设置 ID,通过 ID 获取选中项,不用一个个判断
isChecked()。
4.2 QButtonGroup 的核心 API 详解
4.2.1 创建 QButtonGroup
函数原型:
explicit QButtonGroup::QButtonGroup(QObject *parent = nullptr);
参数说明:
parent:父对象,通常传入this(当前窗口),这样窗口销毁时,QButtonGroup 会自动销毁,不用手动 delete。
调用示例:
// 创建一个 QButtonGroup,父对象是当前窗口
QButtonGroup *genderGroup = new QButtonGroup(this);
4.2.2 添加按钮到组
函数原型:
void QButtonGroup::addButton(QAbstractButton *button, int id = -1);
参数说明:
button:要添加的按钮指针(可以是 QRadioButton、QPushButton、QCheckBox);id:可选参数,给按钮设置一个整数 ID,方便后续通过 ID 获取选中项,默认是 -1(不设置 ID)。
调用示例:
// 添加按钮到组,不设置 ID
genderGroup->addButton(ui->radioButton_male);
genderGroup->addButton(ui->radioButton_female);
genderGroup->addButton(ui->radioButton_other);
// 添加按钮到组,同时设置 ID(推荐,方便获取选中项)
genderGroup->addButton(ui->radioButton_male, 0);
genderGroup->addButton(ui->radioButton_female, 1);
genderGroup->addButton(ui->radioButton_other, 2);
4.2.3 获取当前选中的按钮
函数原型 1:
QAbstractButton* QButtonGroup::checkedButton() const;
- 返回值 :当前选中的按钮指针,如果没有选中项,返回
nullptr。
函数原型 2:
int QButtonGroup::checkedId() const;
- 返回值:当前选中的按钮的 ID,如果没有选中项,返回 -1(需要先给按钮设置 ID)。
调用示例:
// 方式一:获取选中的按钮指针
QAbstractButton *checkedBtn = genderGroup->checkedButton();
if (checkedBtn) {
qDebug() << "当前选中的按钮文本:" << checkedBtn->text();
}
// 方式二:获取选中的按钮 ID(推荐,更简洁)
int checkedId = genderGroup->checkedId();
switch (checkedId) {
case 0:
qDebug() << "选中了男";
break;
case 1:
qDebug() << "选中了女";
break;
case 2:
qDebug() << "选中了其他";
break;
default:
qDebug() << "未选中任何项";
break;
}
4.2.4 QButtonGroup 的核心信号
QButtonGroup 也提供了信号,方便监听组内按钮的选中状态变化,最常用的有两个:
信号 1:
void QButtonGroup::buttonClicked(QAbstractButton *button);
- 触发时机:组内有按钮被点击时触发;
- 参数 :
button- 被点击的按钮指针。
信号 2:
void QButtonGroup::buttonToggled(QAbstractButton *button, bool checked);
- 触发时机:组内有按钮的选中状态变化时触发;
- 参数 :
button- 选中状态变化的按钮指针;checked- 按钮当前的选中状态(true= 选中,false= 取消选中)。
调用示例:
// 关联 buttonToggled 信号,监听选中状态变化
connect(genderGroup, QOverload<QAbstractButton*, bool>::of(&QButtonGroup::buttonToggled), this, [=](QAbstractButton *button, bool checked) {
if (checked) {
qDebug() << "组内选中状态变化,当前选中的按钮:" << button->text();
ui->label->setText("你选择的性别为:" + button->text());
}
});
⚠️ 注意 :这里用了 QOverload 来区分重载的信号,因为 QButtonGroup 的 buttonToggled 有两个重载版本(一个带 ID,一个带按钮指针),Qt5 中需要用 QOverload 来明确指定用哪个版本。
示例代码:
cpp
#include "widget.h"
#include <QApplication>
#include <QButtonGroup>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
//OK,那么上个文件我们说了QRadioButton的排他性,但是我们又不想所有的单选框都被影响
//不同类别的单选框不应该被影响,所以就有了QButtonGroup来进行分组~~~
//来看看~~~
/**
* @class QButtonGroup
* @brief Qt中用于逻辑分组管理按钮控件的核心工具类
* @details QButtonGroup是Qt提供的非可视化容器类(继承自QObject),核心作用是对一组按钮控件(QRadioButton、QPushButton、QCheckBox等)进行**逻辑分组管理**,
* 解决手动管理多按钮选中状态、互斥逻辑、信号监听的繁琐问题;
* 该类不具备可视化界面,仅负责按钮的逻辑关联,可独立于父控件实现按钮分组(弥补QRadioButton仅依赖父控件排他的局限性),
* 同时支持为按钮设置唯一标识(ID),简化选中按钮的识别逻辑,是管理多按钮交互的高效工具。
*
* 【核心特性(通俗理解)】
* 1. 逻辑分组:无需依赖父控件(如QGroupBox),即可将任意按钮划入同一逻辑组,实现组内交互管理;
* 2. 灵活互斥:可手动控制组内按钮是否互斥(选中一个取消其他),突破QRadioButton默认仅按父控件排他的限制;
* 3. 选中管理:提供统一接口获取/设置组内选中按钮,支持按ID或按钮对象操作;
* 4. 信号简化:封装组内按钮的选中状态变化信号(如buttonClicked、buttonToggled),无需为每个按钮单独关联信号。
*
* 【继承关系说明】
* QButtonGroup → QObject(Qt核心基类,无可视化能力)
* 注:QButtonGroup不是QWidget子类,无法直接显示在界面上,仅负责逻辑管理。
*
* 【核心API详解】
* ===================================== 1. 构造函数 =====================================
* 1.1 QButtonGroup(QObject *parent = nullptr)
* - 功能:创建按钮组对象
* - 参数:parent - 父对象,用于Qt的父子对象内存管理(推荐设置为窗口/控件,避免内存泄漏)
* - 示例:
* QButtonGroup* btnGroup = new QButtonGroup(this); // 父对象为当前窗口
*
* ===================================== 2. 按钮添加/移除 =====================================
* 2.1 void addButton(QAbstractButton *button, int id = -1)
* - 功能:将按钮添加到按钮组,并可设置唯一标识ID
* - 参数:
* - button:待添加的按钮对象(QRadioButton、QPushButton等QAbstractButton子类);
* - id:按钮的唯一整数标识(可选,默认-1;建议设置非负整数,便于快速识别按钮);
* - 注意:同一按钮只能加入一个按钮组,重复添加会被忽略;
* - 示例:
* QRadioButton* radio1 = new QRadioButton("选项1", this);
* btnGroup->addButton(radio1, 1); // 添加按钮并设置ID为1
*
* 2.2 void removeButton(QAbstractButton *button)
* - 功能:将按钮从按钮组中移除
* - 参数:button - 待移除的按钮对象;
* - 注意:移除后按钮与组的逻辑关联断开,不影响按钮的可视化显示;
* - 示例:
* btnGroup->removeButton(radio1); // 移除radio1按钮
*
* ===================================== 3. 互斥性控制 =====================================
* 3.1 bool exclusive() const
* - 功能:获取按钮组的互斥状态
* - 返回值:bool类型;true表示组内按钮互斥(选中一个取消其他),false表示不互斥;
* - 注:默认状态下,QButtonGroup的exclusive为true(与QRadioButton默认行为一致);
* - 示例:
* bool isExclusive = btnGroup->exclusive();
*
* 3.2 void setExclusive(bool exclusive)
* - 功能:设置组内按钮是否互斥
* - 参数:exclusive - true开启互斥,false关闭互斥;
* - 适用场景:
* ✅ 开启(true):实现单选逻辑(如性别选择);
* ✅ 关闭(false):实现多选逻辑(如兴趣标签);
* - 示例:
* btnGroup->setExclusive(true); // 开启互斥(默认)
*
* ===================================== 4. 选中按钮管理 =====================================
* 4.1 QAbstractButton *checkedButton() const
* - 功能:获取组内当前被选中的按钮对象
* - 返回值:QAbstractButton*;无选中按钮时返回nullptr;
* - 示例:
* QAbstractButton* selectedBtn = btnGroup->checkedButton();
* if (selectedBtn) {
* qDebug() << "选中按钮文本:" << selectedBtn->text();
* }
*
* 4.2 int checkedId() const
* - 功能:获取组内当前被选中按钮的ID
* - 返回值:int类型;无选中按钮时返回-1;
* - 优势:无需判断按钮对象,直接通过ID识别选中项,简化逻辑;
* - 示例:
* int selectedId = btnGroup->checkedId();
* switch (selectedId) {
* case 1: qDebug() << "选中了选项1"; break;
* case 2: qDebug() << "选中了选项2"; break;
* default: qDebug() << "未选中任何选项";
* }
*
* 4.3 void setExclusive(bool exclusive)
* - 功能:设置组内按钮是否互斥(重复说明,核心重点)
* - 补充:即使组内是QPushButton,开启互斥后也可实现单选逻辑(默认QPushButton无选中状态,需先设置setCheckable(true))。
*
* ===================================== 5. 核心信号(简化监听) =====================================
* 5.1 void buttonClicked(QAbstractButton *button)
* - 触发时机:组内任意按钮被点击时触发;
* - 参数:被点击的按钮对象;
* - 优势:无需为每个按钮单独关联clicked信号,统一监听;
* - 示例:
* connect(btnGroup, &QButtonGroup::buttonClicked, this, [=](QAbstractButton* btn) {
* qDebug() << "点击的按钮:" << btn->text();
* });
*
* 5.2 void buttonClicked(int id)
* - 触发时机:组内任意按钮被点击时触发;
* - 参数:被点击按钮的ID(未设置ID则为-1);
* - 优势:直接通过ID识别按钮,无需类型转换;
* - 示例:
* connect(btnGroup, QOverload<int>::of(&QButtonGroup::buttonClicked), this, [=](int id) {
* qDebug() << "点击的按钮ID:" << id;
* });
*
* 5.3 void buttonToggled(QAbstractButton *button, bool checked)
* - 触发时机:组内按钮选中状态(checked)变化时触发;
* - 参数:
* - button:状态变化的按钮对象;
* - checked:当前是否被选中;
* - 适用场景:监听单选按钮/可选中按钮的选中状态变化;
* - 示例:
* connect(btnGroup, &QButtonGroup::buttonToggled, this, [=](QAbstractButton* btn, bool checked) {
* if (checked) {
* qDebug() << "选中按钮:" << btn->text();
* }
* });
*
* 【典型使用示例】
* ===================================== 示例1:基础单选分组(替代QGroupBox) =====================================
* // 需求:实现性别选择的单选逻辑,无需依赖QGroupBox
* // 步骤1:创建按钮组并开启互斥(默认开启)
* QButtonGroup* genderGroup = new QButtonGroup(this);
*
* // 步骤2:创建单选按钮并添加到组(设置ID)
* QRadioButton* radioMale = new QRadioButton("男", this);
* QRadioButton* radioFemale = new QRadioButton("女", this);
* genderGroup->addButton(radioMale, 1);
* genderGroup->addButton(radioFemale, 2);
*
* // 步骤3:监听选中状态(通过ID)
* connect(genderGroup, QOverload<int>::of(&QButtonGroup::buttonClicked), this, [=](int id) {
* if (id == 1) {
* qDebug() << "选中男性";
* } else if (id == 2) {
* qDebug() << "选中女性";
* }
* });
*
* ===================================== 示例2:QPushButton实现单选逻辑 =====================================
* // 需求:让普通QPushButton具备单选特性(默认QPushButton无选中状态)
* // 步骤1:创建按钮组
* QButtonGroup* btnGroup = new QButtonGroup(this);
* btnGroup->setExclusive(true); // 开启互斥
*
* // 步骤2:创建QPushButton并设置可选中(checkable=true)
* QPushButton* btn1 = new QPushButton("选项1", this);
* QPushButton* btn2 = new QPushButton("选项2", this);
* btn1->setCheckable(true);
* btn2->setCheckable(true);
*
* // 步骤3:添加到按钮组
* btnGroup->addButton(btn1, 1);
* btnGroup->addButton(btn2, 2);
*
* // 效果:点击btn1则btn1选中、btn2取消选中,实现QPushButton的单选逻辑
*
* ===================================== 示例3:获取当前选中项 =====================================
* // 主动获取组内选中的按钮(如点击确认按钮时)
* void Widget::on_confirmBtn_clicked() {
* int selectedId = genderGroup->checkedId();
* if (selectedId == -1) {
* qDebug() << "未选中任何选项";
* } else {
* qDebug() << "选中ID:" << selectedId;
* }
* }
*
* 【关键注意事项】
* 1. 内存管理:QButtonGroup仅管理按钮的逻辑关联,不负责按钮的内存释放;按钮的内存由其父控件(如窗口)管理,需保证按钮的父对象有效;
* 2. 互斥范围:QButtonGroup的互斥仅作用于组内按钮,与父控件无关,可实现跨父控件的按钮单选;
* 3. QPushButton适配:让QPushButton支持选中/互斥,需先调用setCheckable(true)(默认false),否则checkedButton()始终返回nullptr;
* 4. ID唯一性:建议为每个按钮设置唯一ID(非负整数),避免ID重复导致识别错误;未设置ID时,checkedId()返回-1;
* 5. 信号重载:buttonClicked信号有两个重载版本(传按钮对象/传ID),使用Lambda表达式时需通过QOverload指定重载类型,避免编译错误;
* 6. 与QGroupBox的区别:QGroupBox是可视化分组控件(带边框/标题),QButtonGroup是逻辑分组工具;可结合使用(QGroupBox负责界面展示,QButtonGroup负责逻辑管理)。
*/
//那么我们其实也就很清楚了,就是一个类别(组)就创建一个QButtonGroup对象即可
//然后我们再把要在同一个组的按钮都通过QButtonGroup对象的addButton函数传入即可~~~
//还是很简单的~~~
// 创建三个 QButtonGroup
QButtonGroup* group1 = new QButtonGroup(this);
QButtonGroup* group2 = new QButtonGroup(this);
QButtonGroup* group3 = new QButtonGroup(this);
// 把 QRadioButton 两两一组, 放到三个 QButtonGroup 中.
// group1->addButton(ui->radioButton);
// group1->addButton(ui->radioButton_2);
// group2->addButton(ui->radioButton_3);
// group2->addButton(ui->radioButton_4);
// group3->addButton(ui->radioButton_5);
// group3->addButton(ui->radioButton_6);
//需要注意的就是,QButtonGroup是支持几乎所有按钮的哦~~~,这一点要注意,其他的就还是很简单,包括它的其他API~~~
return a.exec();
}
4.3 典型代码示例(麦当劳点餐分组,一看就懂)
这个场景非常经典,模拟麦当劳点餐,有三组独立的单选:主食(汉堡 / 鸡肉卷)、饮料(可乐 / 雪碧)、甜点(冰淇淋 / 薯条),用 QButtonGroup 分组,组内互斥,组间独立:
#include "widget.h"
#include "ui_widget.h"
#include <QRadioButton>
#include <QButtonGroup>
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 步骤1:创建三个 QButtonGroup,分别对应主食、饮料、甜点
QButtonGroup *foodGroup = new QButtonGroup(this);
QButtonGroup *drinkGroup = new QButtonGroup(this);
QButtonGroup *dessertGroup = new QButtonGroup(this);
// 步骤2:把按钮添加到对应的组里,并设置 ID
// 主食组
foodGroup->addButton(ui->radioButton_hamburger, 0); // 汉堡,ID=0
foodGroup->addButton(ui->radioButton_wrap, 1); // 鸡肉卷,ID=1
ui->radioButton_hamburger->setChecked(true); // 默认选中汉堡
// 饮料组
drinkGroup->addButton(ui->radioButton_cola, 0); // 可乐,ID=0
drinkGroup->addButton(ui->radioButton_sprite, 1); // 雪碧,ID=1
ui->radioButton_cola->setChecked(true); // 默认选中可乐
// 甜点组
dessertGroup->addButton(ui->radioButton_icecream, 0); // 冰淇淋,ID=0
dessertGroup->addButton(ui->radioButton_fries, 1); // 薯条,ID=1
ui->radioButton_icecream->setChecked(true); // 默认选中冰淇淋
// 步骤3:关联"确认订单"按钮的点击信号,获取选中项
connect(ui->pushButton_confirm, &QPushButton::clicked, this, [=]() {
// 获取主食选中项
int foodId = foodGroup->checkedId();
QString foodText = (foodId == 0) ? "汉堡" : "鸡肉卷";
// 获取饮料选中项
int drinkId = drinkGroup->checkedId();
QString drinkText = (drinkId == 0) ? "可乐" : "雪碧";
// 获取甜点选中项
int dessertId = dessertGroup->checkedId();
QString dessertText = (dessertId == 0) ? "冰淇淋" : "薯条";
// 输出订单
qDebug() << "你的订单:";
qDebug() << "主食:" << foodText;
qDebug() << "饮料:" << drinkText;
qDebug() << "甜点:" << dessertText;
});
}
Widget::~Widget()
{
delete ui;
}


4.4 关键注意事项
- QButtonGroup 是不可见的:它只是一个辅助类,不会显示在界面上,不用考虑它的位置和大小;
- 排他性默认开启 :QButtonGroup 默认会让组内的 QRadioButton 互斥,无需手动设置;如果是 QPushButton 或 QCheckBox,需要手动设置
setCheckable(true); - ID 要唯一 :同一组内的按钮 ID 最好唯一,方便通过
checkedId()获取选中项; - 父控件与 QButtonGroup 的优先级:如果按钮同时在一个父控件组和一个 QButtonGroup 里,QButtonGroup 的分组优先级更高,以 QButtonGroup 为准。
完整示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,本文件我们来学习QRadioButtion的属性
//什么是QRadioButton呢?其实我们之前学习前端就有接触过了
//这个就是一个单选框~~~一下子就想起了单选题了~~~
//那么它有什么属性呢?其实啊,它是QWidget和QAbtractButton(QPushButton)的子类
//所以我们之前介绍的QWidget、QPushButton的属性,它都可以用
//那么它自己的属性是哪些呢?其实是简单的:
/**
* @class QRadioButton
* @brief Qt中的单选按钮控件类
* @details QRadioButton是实现"多选一"交互逻辑的核心控件,适用于从多个互斥选项中选择一个的场景(如性别选择、版本类型选择、功能模式切换等);
* 该类继承自QAbstractButton抽象类(所有按钮类的基类),且QAbstractButton继承自QWidget,因此QWidget及QAbstractButton的所有属性、方法均适用于QRadioButton;
* QRadioButton的核心交互逻辑由QAbstractButton的checkable、checked、autoExclusive三个属性支撑,其中autoExclusive属性默认开启,是实现"单选"特性的关键。
*
* 【继承关系说明】
* QRadioButton → QAbstractButton(抽象类,所有按钮控件的父类) → QWidget(所有界面控件的基类)
* QWidget及QAbstractButton的通用属性(如text、icon、styleSheet等)均适用于QRadioButton,使用方式无差异。
*
* 【QAbstractButton核心属性(QRadioButton重点依赖)】
* 以下属性是QRadioButton实现单选逻辑的核心,均遵循Qt统一的"获取(isXxx())+ 设置(setXxx())"API设计风格:
*
* ===================================== 属性1:checkable =====================================
* • 数据类型:bool
* • 核心作用:控制单选按钮是否具备"被选中/取消选中"的交互能力,是checked属性生效的前置条件;
* 若该属性为false,按钮无法被选中(checked属性始终为false),仅作为普通文本按钮显示;若为true,按钮可被点击切换选中状态。
* • 关联API:
* 1. bool isCheckable() const
* - 功能:获取按钮是否具备可选中能力
* - 返回值:bool类型;true表示可选中,false表示不可选中;QRadioButton默认值为true
* - 调用示例:
* bool canCheck = ui->radioButton->isCheckable(); // 读取可选中状态
*
* 2. void setCheckable(bool enable)
* - 功能:设置按钮是否可被选中
* - 参数:enable - true开启可选中能力,false关闭
* - 生效规则:调用后立即生效,关闭后checked属性无法被修改
* - 调用示例:
* ui->radioButton->setCheckable(true); // 开启可选中(默认状态,无需手动设置)
* ui->radioButton->setCheckable(false); // 关闭可选中,按钮变为普通不可选状态
* • 关键注意事项:
* - checkable是checked属性的前提,若checkable=false,调用setChecked()修改选中状态不会生效;
* - QRadioButton默认checkable=true,无需手动设置,仅在需将其改为"不可选文本按钮"时调整。
*
* ===================================== 属性2:checked =====================================
* • 数据类型:bool
* • 核心作用:表示单选按钮当前是否处于"被选中"状态,仅在checkable为true时生效;
* 选中状态的QRadioButton会显示标志性的"圆点"标记(样式可通过QSS修改),是区分选中/未选中的核心视觉标识。
* • 关联API:
* 1. bool isChecked() const
* - 功能:获取按钮当前的选中状态
* - 返回值:bool类型;true表示已选中,false表示未选中;QRadioButton默认值为false
* - 调用示例:
* bool isSelected = ui->radioBtnMale->isChecked(); // 判断"男"单选按钮是否被选中
*
* 2. void setChecked(bool checked)
* - 功能:手动设置按钮的选中状态
* - 参数:checked - true设为选中状态,false设为未选中状态
* - 生效规则:仅当checkable=true时生效;若autoExclusive=true,设置为true会自动取消同组其他按钮的选中状态
* - 调用示例:
* ui->radioBtnMale->setChecked(true); // 手动选中"男"单选按钮
* • 关键注意事项:
* - 点击选中状态的QRadioButton不会自动取消选中(需通过代码调用setChecked(false),或依赖autoExclusive由其他按钮触发取消);
* - 可通过toggled(bool checked)信号监听选中状态变化(checked参数为true表示选中,false表示取消选中)。
*
* ===================================== 属性3:autoExclusive =====================================
* • 数据类型:bool
* • 核心作用:控制同一父控件下的多个QRadioButton是否具备"互斥选中"特性(即"单选"核心逻辑);
* 当autoExclusive=true时,选中其中一个按钮,会自动取消同组(同一父控件)其他按钮的选中状态;
* 当autoExclusive=false时,多个按钮可被同时选中(失去单选特性,行为接近复选框QCheckBox)。
* • 关联API:
* 1. bool autoExclusive() const
* - 功能:获取按钮的排他性状态
* - 返回值:bool类型;true表示开启排他,false表示关闭;QRadioButton默认值为true
* - 调用示例:
* bool isExclusive = ui->radioButton->autoExclusive(); // 读取排他性状态
*
* 2. void setAutoExclusive(bool enable)
* - 功能:设置按钮是否开启排他性
* - 参数:enable - true开启排他(默认),false关闭排他
* - 生效规则:调用后立即生效,排他性作用于同一父控件下的所有QRadioButton
* - 调用示例:
* ui->radioButton->setAutoExclusive(true); // 开启排他(默认状态,无需手动设置)
* ui->radioButton->setAutoExclusive(false); // 关闭排他,允许同组多个按钮被选中
* • 关键注意事项:
* - "同组"定义:同一父控件(如QWidget、QGroupBox)下的所有QRadioButton;若需实现多组单选(如"性别"和"学历"两组单选),需将不同组的按钮放入不同的父控件(如QGroupBox)中;
* - 关闭autoExclusive后,QRadioButton的行为与QCheckBox(复选框)无本质差异,需根据业务场景选择是否关闭。
*
* 【典型使用示例】
* ===================================== 示例:性别选择单选按钮组 =====================================
* // 1. 创建两个单选按钮(父控件为当前窗口,默认开启autoExclusive,实现互斥选中)
* QRadioButton* radioMale = new QRadioButton("男", this);
* QRadioButton* radioFemale = new QRadioButton("女", this);
*
* // 2. 无需手动设置checkable/autoExclusive(默认值已满足需求)
* // 3. 手动选中"男"按钮
* radioMale->setChecked(true);
*
* // 4. 监听选中状态变化
* connect(radioMale, &QRadioButton::toggled, this, [=](bool checked) {
* if (checked) {
* qDebug() << "选中了「男」选项";
* }
* });
* connect(radioFemale, &QRadioButton::toggled, this, [=](bool checked) {
* if (checked) {
* qDebug() << "选中了「女」选项";
* }
* });
*
* ===================================== 示例:多组单选按钮(分组实现) =====================================
* // 需求:实现"性别"和"学历"两组独立的单选按钮
* // 步骤1:创建两个QGroupBox作为分组容器
* QGroupBox* genderGroup = new QGroupBox("性别", this);
* QGroupBox* eduGroup = new QGroupBox("学历", this);
*
* // 步骤2:将不同组的单选按钮放入对应QGroupBox
* QRadioButton* radioMale = new QRadioButton("男", genderGroup);
* QRadioButton* radioFemale = new QRadioButton("女", genderGroup);
* QRadioButton* radioHigh = new QRadioButton("本科", eduGroup);
* QRadioButton* radioMaster = new QRadioButton("硕士", eduGroup);
*
* // 效果:genderGroup内的按钮互斥,eduGroup内的按钮互斥,两组之间无影响
*
* 【关键注意事项】
* 1. 选中状态切换:点击未选中的QRadioButton会使其选中(autoExclusive=true时取消同组其他选中),但点击已选中的QRadioButton不会自动取消选中(需代码实现);
* 2. 样式自定义:QRadioButton的选中圆点样式可通过QSS修改(如修改颜色、大小),核心属性为::indicator(指示器);
* 3. 信号监听:推荐使用toggled(bool checked)信号监听选中状态变化,而非clicked()(clicked信号无法区分选中/取消选中)。
*/
}
Widget::~Widget()
{
delete ui;
}
第五章 全文总结与学习建议
恭喜你!终于看完了这篇 QRadioButton 与 QButtonGroup 详细解析!
如果你跟着文章一步步敲了代码,做了练习,那么现在你已经完全掌握了 QRadioButton 最核心的内容:
- 你会用
checkable控制按钮是否可选中,用checked标识选中状态,用autoExclusive实现单选逻辑; - 你知道了四个信号的区别,明白为什么
toggled是最适合 QRadioButton 的信号; - 你会用 QGroupBox 或 QButtonGroup 实现多组独立的单选,组内互斥,组间独立;
- 你还知道了怎么用 QButtonGroup 的 ID 快速获取选中项,不用一个个判断。
毫不夸张地说,掌握了这些内容,你就掌握了 QRadioButton 开发的 90% 以上的需求!接下来,你可以用这些内容,实现各种你想要的单选交互了。
5.1 核心要点回顾
在结束之前,我们最后再回顾一下这篇文章的核心要点:
- 继承关系:QRadioButton → QAbstractButton → QWidget,QWidget 和 QAbstractButton 的所有属性 QRadioButton 都能用;
- checkable 是 checked 的前提 :必须先确保
checkable=true,setChecked()才会生效; - autoExclusive 是单选的核心 :默认
true,同组(同一父控件或同一 QButtonGroup)内互斥; - toggled 是首选信号 :仅响应选中状态变化,携带
checked参数,能精准捕获用户选择; - 分组方式:可以用不同父控件(如 QGroupBox)分组,也可以用 QButtonGroup 分组,QButtonGroup 更灵活,还能设置 ID;
- 样式自定义 :QRadioButton 的选中圆点样式可通过 QSS 修改,核心属性为
::indicator(指示器)。
5.2 最后的话
编程学习没有捷径,唯手熟尔。QRadioButton 的属性和信号虽然看起来很多,但只要你多敲代码、多做练习、多踩坑、多排查,很快就能熟练掌握。
这篇文章虽然很长,但我相信,如果你认真看完了,跟着敲了代码,你一定会对 QRadioButton 和 QButtonGroup 有一个极其深刻的理解,再也不会为单选逻辑发愁。
感谢你阅读这篇文章,希望它能帮到你。我们下一篇 Qt 教程再见!