欢迎文末添加好友交流,共同进步!
- 目录
- 一、为什么要先了解 QWidget
- 1.1 QWidget 是所有控件的基类
- 1.2 在 Qt Creator 中查看和编辑属性
- 1.3 这么多属性,不需要全背
- 二、Enabled 属性到底是什么
- 2.1 可用 vs 禁用
- 2.2 禁用状态的三大表现
- 2.3 灰色头像不会再跳动
- 三、Enabled 相关的 API
- 四、UI 控件的 objectName 命名规范
- 4.1 objectName 是什么
- 4.2 objectName 必须唯一
- 4.3 自动命名的规律
- 4.4 不要用数字命名!
- 五、clicked 信号的两个版本
- 六、代码实操
- 【实操 1】创建一个禁用按钮
- 【实操 2】通过按钮动态切换禁用状态
目录
前面几个章节我们讲完了信号槽机制,从本章节开始,我们正式进入 Qt 控件体系的学习!不过在介绍各种内置控件之前,我们得先聊一聊
QWidget这个"祖宗类"——毕竟 Qt 里的各种控件都继承自它,把它里面通用的属性方法搞清楚了,后续学其他控件就能事半功倍!
一、为什么要先了解 QWidget
我们前面其实就已经多次接触到QWidget了,比如创建项目时基类就选它。这里我们再系统地认识一下。
1.1 QWidget 是所有控件的基类
Qt 中的各种控件——QPushButton(按钮)、QLabel(标签)、QLineEdit(输入框)、QMainWindow(主窗口)等等——全部都继承自QWidget这个类。
这就意味着什么呢?意味着QWidget里提供的属性和方法,会被它所有的子类统统继承下来。换句话说,QWidget里的属性方法是整个 Qt 控件体系中通用的基础能力。
所以这块内容是我们首先要了解的——你把QWidget的通用属性学明白了,后面再学任何一个具体的控件(不管是按钮、标签还是输入框),这些属性它都继承下来都能用!这不是学一次的事,是学一次用一辈子的事。
1.2 在 Qt Creator 中查看和编辑属性
我们直接打开 Qt Creator,切到之前的项目里。由于我们前面创建的窗口就是基于QWidget的,所以此时鼠标选中窗口,右侧的属性面板就会显示出当前QWidget提供的各种属性。
这里有两点很方便:
- 能查看:右侧面板列出了
QWidget的所有公开属性,一目了然- 能编辑:不光能看,还能直接在面板里修改这些属性的值
这些属性都是什么含义呢?其实这些属性还是挺多的,我们都可以通过 Qt 官方文档来一一了解。
1.3 这么多属性,不需要全背
但是话又说回来了,这么多属性,我们并不需要把每一个属性都搞得清清楚楚。这个其实也没啥太大的必要,为啥呢?(⊙_⊙)?
跟给你一本英文词典是一样的道理——你并不需要把这本词典里面所有的词、所有的每一句话都背下来。很多东西都是用的时候再去查。
所以我这里也只是给大家介绍一些比较重要的、比较常用的属性。下面我也给大家提供了一个属性对照表,把QWidget在 Qt Creator 中所显示出的这些属性都列出来了,并且针对每一个属性做了简单的讲解。感兴趣的同学可以自己浏览一下这个表格扩展了解。
Qt Widget 常用属性汇总表
| 属性 | 作用 |
|---|---|
| enabled | 设置控件是否可使用。true表示可用,false表示禁用。 |
| geometry | 位置和尺寸。包含x,y,width,height四个部分,坐标以父元素为参考。 |
| windowTitle | 设置Widget的窗口标题。 |
| windowIcon | 设置Widget的窗口图标。 |
| windowOpacity | 设置Widget的透明度。 |
| cursor | 鼠标悬停时显示的图标形状,如普通箭头、沙漏、十字等。可在Qt Designer中直观选择。 |
| font | 字体相关属性,涉及字体家族、大小、粗体、斜体、下划线等样式。 |
| toolTip | 鼠标悬停在Widget上时,在状态栏中显示的提示信息。 |
| toolTipDuring | toolTip提示信息的显示持续时间。 |
| statusTip | Widget状态发生改变时(如按钮被按下)在状态栏显示的提示信息。 |
| whatsThis | 鼠标悬停并按下Alt+F1时,在弹出窗口中显示的帮助信息。 |
| styleSheet | 允许使用CSS样式表来设置Widget的样式,样式定制能力非常丰富。 |
| focusPolicy | 控件获取焦点的方式。 • Qt::NoFocus:不参与焦点管理。• Qt::TabFocus:可通过Tab键获得焦点。• Qt::ClickFocus:可通过鼠标点击获得焦点。• Qt::StrongFocus:可通过键盘和鼠标获得焦点。• Qt::WheelFocus:可通过鼠标滚轮获得焦点(部分平台或样式可能不可用)。 |
| contextMenuPolicy | 上下文菜单的显示策略。 • Qt::DefaultContextMenu:默认策略,鼠标右键或键盘快捷键可触发。• Qt::NoContextMenu:禁用上下文菜单。• Qt::PreventContextMenu:阻止控件显示上下文菜单。• Qt::ActionsContextMenu:将菜单替换为控件的“动作”菜单。• Qt::CustomContextMenu:使用自定义的上下文菜单。 |
| locale | 设置语言和国家地区。 |
| acceptDrops | 该部件是否接受拖放操作。为true时可接收来自其他部件的拖放,并触发相应事件(如dropEvent);为false则不接收。 |
| minimumSize | 控件的最小尺寸,包含最小宽度和最小高度。 |
| maximumSize | 控件的最大尺寸,包含最大宽度和最大高度。 |
| sizePolicy | 尺寸策略,设置控件在布局管理器中的缩放方式。 |
| windowModality | 指定窗口是否具有“模态”行为。 |
| sizeIncrement | 拖动窗口大小时的增量单位。 |
| baseSize | 窗口的基础大小,与sizeIncrement配合使用,用于计算组件应调整到的合适尺寸。 |
| palette | 调色板,用于设置Widget的颜色风格。 |
| mouseTracking | 是否跟踪鼠标移动事件。 • true:鼠标划过时Widget持续收到鼠标移动事件。• false:鼠标划过时Widget只收到按下或释放事件,不收到移动事件。 |
| tabletTracking | 是否跟踪触摸屏的移动事件,类似于mouseTracking,是Qt 5.9引入的属性。 |
| layoutDirection | 布局方向。 • Qt::LeftToRight:从左到右排列(默认)。• Qt::RightToLeft:从右到左排列。• Qt::GlobalAtomics:由应用程序中其他Widget的布局方向决定。 |
| autoFillBackground | 是否自动填充背景颜色。 |
| windowFilePath | 将Widget与一个本地文件路径关联起来(实际作用不大)。 |
| accessibleName | 设置Widget的可访问名称,可被屏幕阅读器等辅助技术获取,用于无障碍程序场景。 |
| accessibleDescription | 设置Widget的详细描述,作用同accessibleName。 |
| inputMethodHints | 针对输入框有效,提示用户当前可输入的合法数据格式,如只能输入数字或日期等。 |
我们接下来要做的,就是从这些属性里挑出几个比较重要的、比较常用的,单独拎出来,配合代码给大家演示效果。我们第一个要介绍的重要属性,就叫做Enabled。
二、Enabled 属性到底是什么
2.1 可用 vs 禁用
这个所谓的Enabled,其实也比较好理解,它描述的是一个控件是否处于"可用"这样的状态。
什么叫可用?与"可用"相对的另外一个概念叫做禁用:
- 可用(enabled):你可以正常去使用它。我们之前创建的按钮、输入框啥的,默认都属于可用状态。
- 禁用(disabled):这个控件当前无法使用了。
那"禁用"到底是什么效果?主要有以下三点。
2.2 禁用状态的三大表现
第一,不能接收任何用户的输入事件。
什么意思?就是禁用状态下,你这个控件就不能再去接收任何用户的输入事件了——鼠标往上一点,没啥反应;键盘怎么去摁,也没啥反应。你不管怎么操作,它都不会去鸟你了,完全无视。
第二,外观上会显示成一个灰色的状态。
就是灰了嘛,看起来就是点不了的样子。这个大家平时用软件应该也见过,一个按钮变灰了你就知道它现在点不了。
第三,子元素会跟着一起被禁用(重点!)
大家不要忘了,在 Qt 中我们的控件对象可都是以对象树的方式来组织的。这就意味着——
如果一个控件被禁用了,那么这个控件它的子元素也会被禁用。
它属于是"一荣俱荣,一损俱损"。你把这棵对象树上其中某个节点的控件设为禁用了,那这个控件下面的所有子控件也就被禁用了。所以禁用是会沿着对象树向下传递的。
这一点特别重要!如果你以后发现一个控件怎么点都没反应,除了检查它自己有没有被禁用,还得往上看看它的父控件是不是被禁用了。
2.3 灰色头像不会再跳动
讲到禁用状态这个灰色的效果,就恍然间让我想起一首许嵩的歌——不知道同学们有没有听过,叫《灰色头像》?其中怎么唱来着?
“你灰色头像不会再跳动”
灰色头像不会再跳动,意味着什么?意味着你再给他发消息都不会再有响应了!这跟我们禁用控件是一模一样的——按钮变灰了,意思就是你再怎么点它都没用了。所以这还真是一个挺悲伤的故事啊。
三、Enabled 相关的 API
那我们如何去获取和设置一个控件的 enabled 状态呢?回到课件上,这里列出了相关的 API。
| API | 返回值 | 说明 |
|---|---|---|
isEnabled() | bool | 获取当前控件是否可用。true就是可用,false就是禁用 |
setEnabled(bool) | void | 设置当前控件是否可用。传true设为可用,传false设为禁用 |
人家这个方法名字呢,起得也是非常直观——isEnabled就是"是否可用",setEnabled就是"设置是否可用",基本上一看名字咱们就能知道它是如何使用的。true/false对应可用/禁用,一目了然。
四、UI 控件的 objectName 命名规范
在正式写代码演示之前,我们先得补充一个非常关键的知识点——objectName 命名规范。这个知识点在我们通过 UI 文件拖拽创建控件的时候非常重要,是后面写代码的基础,必须搞清楚。
4.1 objectName 是什么
当我们通过 UI 文件(也就是 Qt Designer 设计器)拖拽创建控件的时候,每个控件都会有一个叫做objectName(对象名)的属性,这个东西非常关键!
比如我们拖一个push button到界面上,选中它,在右侧属性面板里就能看到,它的 objectName 就叫做pushButton。再拖第二个按钮进去,它的 objectName 就叫做pushButton_2。
这个 objectName 有什么用呢?后续我们在 C++ 代码中,就可以通过ui->objectName的方式来获取到对应的控件对象:
ui->pushButton// 得到第一个按钮对象ui->pushButton_2// 得到第二个按钮对象4.2 objectName 必须唯一
这里有一个硬性要求:同一个界面中,不同控件的 objectName 必须不同,不能重复!
换句话说不能重名。为什么呢?这就涉及我前面反复给大家提过的那个元编程技术了。
元编程是怎么回事?
Qt 会根据我们的 UI 文件(
.ui文件),在编译时自动生成一个叫做ui_widget.h的头文件。生成的过程中,Qt 就会感知到这个界面上都有哪些控件、每个控件的 objectName 是什么。然后它就会根据 UI 文件的内容,把这些控件作为成员变量统统定义到生成的
Ui::Widget类里面——控件的 objectName 是什么,成员变量名就叫什么。所以我们写
ui->pushButton能拿到对应的对象,本质上是因为 Qt 在背后根据 objectName 自动帮我们生成了对应的成员变量。如果你的 objectName 重名了,生成的成员变量也就冲突了,所以必须唯一。
4.3 自动命名的规律
仔细观察可以发现,Qt 自动生成的 objectName 是有一定规律的:
控件类型 + 下划线 + 数字
比如QPushButton这个类型,去掉Q前缀就是push button,所以:
- 第一个
QPushButton→pushButton - 第二个
QPushButton→pushButton_2 - 第三个
QPushButton→pushButton_3 - ……依次往后排
4.4 不要用数字命名!
但是!这种以数字方式命名,其实不是一个很好的编程习惯!
为啥?因为数字是没有任何含义的,你看到pushButton_2这个名字,根本不知道这个按钮是干嘛用的。我们还是期望变量名能够见名知义。
所以一般我们不太会直接使用自动生成的名字,而是手动修改成一个更有描述性质的名字。比如一个按钮的作用是"切换可用状态",那我们就把它的 objectName 改成enable或者类似的语义化名字,而不是用默认的pushButton_2。
良好的命名习惯是工程化编码的基本要求。大家从一开始就养成这个习惯,后面写出来的代码可读性会高很多!
五、clicked 信号的两个版本
还有一个前面遗留的小知识点,在这里一并说明。我们在给按钮"转到槽"的时候,会发现clicked信号其实有两个版本:
// 版本 1:无参数voidclicked();// 版本 2:带布尔参数voidclicked(boolchecked);那我们用哪个呢?
对于QPushButton来说,我们一般使用无参数版本即可。
那个带布尔参数的版本里,checked表示的是"当前是否处于一个被勾选的状态"——表示是否被勾选。这件事情对于普通的QPushButton来说,是没有意义的,所以我们不去考虑它。
但是!后续我们介绍到QCheckBox(复选框)、QRadioButton(单选按钮)这种可勾选的按钮类控件时,这个带参版本就有用了。所以这里先记住:普通 PushButton 用无参clicked(),可勾选的 CheckBox / RadioButton 才考虑带参clicked(bool)。
六、代码实操
从这里开始就是实操部分了。以下两个实操需要我们亲自动手完成——创建项目、拖控件、写代码、运行验证。
【实操 1】创建一个禁用按钮
目标:体验一下"禁用"到底长什么样。
操作步骤:
- 创建项目:新建一个项目,起名为
QWidget_1,基类选择QWidget,一路下一步完成 - 写代码:在
Widget.cpp的构造函数里,手动new一个按钮出来,把它设为禁用状态 - 运行观察:看看按钮是不是变灰了,点它有没有反应
- 关联槽函数验证:给按钮连上槽函数,再次运行,确认禁用状态下即使连了槽函数也点不动
代码参考:
#include"widget.h"#include"ui_widget.h"#include<QPushButton>// 使用 QPushButton 需要包含这个头文件#include<QDebug>Widget::Widget(QWidget*parent):QWidget(parent),ui(newUi::Widget){ui->setupUi(this);// new 一个按钮,不要忘了传 this 指定父对象(纳入对象树管理)QPushButton*button=newQPushButton(this);button->setText("按钮");// 把按钮设为禁用状态button->setEnabled(false);}验证要点:
- 运行后,按钮应该是灰色的
- 鼠标点击它,没有任何反应
- 即使你给它关联了槽函数(
connect+ 打印日志),禁用状态下槽函数也不会触发——这跟连不连槽函数没关系,禁用了就是用不了
【实操 2】通过按钮动态切换禁用状态
目标:通过第二个按钮,在程序运行过程中动态切换第一个按钮的可用/禁用状态。
操作步骤:
创建项目:新建项目
QWidget_2,基类选QWidgetUI 搭建:打开
.ui文件,拖入两个按钮:- 第一个按钮:文本设为"按钮",objectName 保持默认
pushButton - 第二个按钮:文本设为"切换可用状态",objectName 手动改为
enable(见名知义!)
- 添加槽函数:分别给两个按钮右键 → 转到槽 → 选择
clicked()→ 确认
- 第一个按钮:文本设为"按钮",objectName 保持默认
- 写槽函数逻辑:
- 第一个按钮的槽函数:打印一条日志,验证它是否被触发
- 第二个按钮的槽函数:先获取第一个按钮的当前状态,然后做取反切换
- 运行验证:点第一个按钮有反应,点第二个按钮后第一个变灰,再点第一个没反应,再点第二个又恢复
代码参考:
// 第一个按钮的槽函数:打印日志,验证是否触发voidWidget::on_pushButton_clicked(){//记得加上头文件!!!#include<QDebug>qDebug()<<"执行了槽函数";}// 第二个按钮的槽函数:切换第一个按钮的禁用状态voidWidget::on_enable_clicked(){// 先获取第一个按钮当前是否可用boolenable=ui->pushButton->isEnabled();if(enable){// 当前可用 -> 设为禁用ui->pushButton->setEnabled(false);}else{// 当前禁用 -> 设为可用ui->pushButton->setEnabled(true);}}验证流程:
- 程序启动,连续点击第一个按钮,观察控制台是否持续打印"执行了槽函数"
- 点击第二个"切换可用状态"按钮,观察第一个按钮是否立刻变灰
- 变灰后再点击第一个按钮,确认无反应、控制台不再打印
- 再点一下第二个按钮,观察第一个按钮是否恢复正常
- 再点第一个按钮,确认又能正常触发了
核心结论:禁用就是按钮变灰,再怎么点都没用。理解了这一点,本章节的目标就达成了!