目录
- 前言
- 一、控件概述
- 二、QWidget核心属性
-
- enabled
- geometry
- [Window Frame](#Window Frame)
- windowTitle
- windowIcon
- windowOpacity
- cursor
- font
- toolTip
- focusPolicy
- styleSheet
前言
书接上文【Qt】信号和槽详情点击查看,今天继续来介绍【Qt】常用控件----QWidget
一、控件概述
- Widget是Qt中的核心概念。英文原义是"小部件",我们此处也把它翻译为"控件"。控件是构成一个图形化界面的基本要素
- Qt作为一个成熟的GUI开发框架,内置了大量的常用控件。这一点在Qt Designer中就可以看到端倪。并且Qt也提供了"自定义控件"的能力,可以让程序猿在现有控件不能满足需求的时候,对现有控件做出扩展,或者手搓出新的控件

二、QWidget核心属性
- 在Qt中,使用QWidget类表示"控件"。像按钮、视图、输入框、滚动条等具体的控件类,都是继承自QWidget,可以说,QWidget中就包含了Qt整个控件体系中通用的部分
- 在Qt Designer中,随便拖一个控件过来,选中该控件,即可在右下方看到QWidget中的属性,这些属性既可以通过Qt Designer直接修改,也可以通过代码的方式修改。这些属性的具体含义在Qt Assistant中均有详细介绍(在Qt Assistant中搜索QWidget 即可找到对应的文档说明(或者在Qt Creator代码中选中QWidget按F1 也可))

enabled
- 作用:设置控件是否可使用:true 表示可用,false 表示禁用
- 所谓"禁用"指的是该控件不能接收任何用户的输入事件,并且外观上往往是灰色的,如果一个widget被禁用,则该widget的子元素也被禁用
| API | 说明 |
|---|---|
| isEnabled() | 获取到控件的可用状态 |
| setEnabled | 设置控件是否可使用。true 表示可用,false 表示禁用 |
- 我们创建一个按钮控件,并当点击按钮之后会打印出handle字样。但是现在我们禁用按钮,查看效果
- 首先按钮是灰色的,点击按钮并没有任何反应

- 我们使用ui文件创建两个按钮,其中一个按钮的功能就是切换另外一个按钮的可用不可用
- 在同一个界面中,要求不同控件的objectName必须是不同的(不能重复),后续通过ui->objectName方式来获取对应控件对象(ui->pushButton,获得第一个按钮对象;ui->pushButton2,获得第二个按钮对象)


- 我们可以发现,objectName的自动生成的名字是控件类型+下划线+数字,我们可以根据控件功能修改objectName,如下图:

- 创建两个按钮的槽函数,按钮1:当按钮可用,点击按钮之后打印日志:执行了槽函数;按钮2:当点击按钮2,则获取按钮1的状态,如果可用,则将状态设置成不可用;如果按钮不可用,则将状态设置成可用

geometry
位置和尺寸,其实是四个属性的统称:
• x:横坐标
• y:纵坐标
• width:宽度
• height:高度
| API | 说明 |
|---|---|
| geometry() | 获取到控件的位置和尺寸,返回结果是⼀个QRect(矩形,QRect.x等来访问x、y...),包含了x、y、width、height。其中x、y是左上角的坐标 |
| setGeometry(QRect)、setGeometry(int x,int y,int width,int height) | 设置控件的位置和尺寸,可以直接设置一个QRect,也可以分四个属性单独设置 |
- 一个按钮控制target按钮向上,一个按钮控制target按钮向下,一个按钮控制target按钮向左,一个按钮控制target按钮向右
-
使用ui文件创建5个按钮,将按钮名字修改为pushButton_target、pushButton_up、pushButton_down、pushButton_left、pushButton_right

-
分别定义槽函数,运行,我们发现不管怎么点击按钮,target按钮没有变化,因为下面代码中,我们修改的是我们在各个函数内部定义的QRect类型rect局部变量,并没有修改target按钮的

-
因此我们要将修改后的rect传入到函数setGeometry(rect)

-
运行代码,点击up按钮发现,target按钮有变化,但是它是y轴变长了,我们想要的是按钮框不变的情况下上下左右移动。当前代码调整的是左上角的位置,同时改变了高度和宽度

-
因此我们不能通过传入Qrect来修改,而是传入x、y、width、height来修改即可

运行结果如下:target按钮能移动且不改变宽度和高度

Window Frame
- 如果widget作为一个窗口(带有标题栏:最小化、最大化、关闭按钮),那么在计算尺寸和坐标的时候就有两种算法:包含window frame和不包含window frame。
- 其中x()、y()、frameGeometry()、pos()、move()都是按照包含window frame的方式来计算的。
- 其中geometry()、width()、height()、rect()、size()则是按照不包含window frame的方式来计算的。
- 当然,如果一个不是作为窗口 的widget,上述两类方式得到的结果是一致的

- 验证geometry()和frameGeometry()的区别
- 从打印日志可以看到两个是完全一样的,这是为什么呢?
- 我们可以看到geometry()和frameGeometry()是放在构造函数中,Widget刚刚创建出来,还没有加入到对象树中,此时也就不具备Window frame,因此还看不到差异

- 现在,我们将geometry()和frameGeometry()代码和按钮关联,点击按钮之后再使用geometry()、frameGeometry()
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button = new QPushButton(this);
button->setText("按钮");
button->move(200, 200);
connect(button, &QPushButton::clicked, this, &Widget::handleClicked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleClicked()
{
QRect rect1 = this->geometry();
QRect rect2 = this->frameGeometry();
qDebug() << rect1;
qDebug() << rect2;
}

windowTitle
- windowTitle属性,只针对顶层widget(独立窗口)的Widget才会有效,如果是子widget,这个操作无任何效果
| API | 说明 |
|---|---|
| windowTitle() | 获取到控件的窗口标题 |
| setWindowTitle(const QString& title) | 设置控件的窗口标题 |
从下面运行结果可以看出,顶层Widget设置窗口标题成功,下面子Widget就算设置了窗口标题没有效果,没有报错
windowIcon
- windowIcon 表示窗口的图标,和windowTitle属性,只针对顶层widget(独立窗口)的Widget才会有效

| API | 说明 |
|---|---|
| windowIcon() | 获取到控件的窗口图标,返回QIcon对象 |
| setWindowIcon(const QIcon& icon) | 设置控件的窗口图标 |
- windowIcon()很少使用,QIcon表示一个图标
- Qlcan自身是一个比较小的对象,创建出来后就是要设置到某个QWidget里面,Qlcon本身释放不释放不影响图标最终的显示(Qlcon不支持对象树,无法给它执行父对象),因此我们不需要在堆上申请(new)
- Windows下路径的分隔符可以使用 / 也可以使用 \ ,但是如果在字符串中使用 \ 需要写作转义字符的形式 \ ,因此我们还是更推荐使用 /
- 现在我们实现将窗口图标替换成我们自己的一张图片。先在D盘中放一个图片,名字为Qt.png
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QIcon>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置图标
QIcon icon("D:/XMind/Qt.png");
this->setWindowIcon(icon);
}
Widget::~Widget()
{
delete ui;
}

- 实际开发中,我们一般不会在代码中通过绝对路径引入图片,因为我们无法保证程序发布后,用户的电脑上也有同样的路径。如果使用相对路径,则需要确保代码中的相对路径写法和图片实际所在的路径匹配(比如代码中写作"./image/Qt.png",就需要在当前工作目录中创建image目录,并把Qt.png放进去)
qrc机制
- qrc文件是⼀种XML格式(后缀名使用.qrc)的资源配置文件,它用XML记录硬盘上的文件和对应的随意指定的资源名称。应用程序通过资源名称来访问这些资源
- 在Qt开发中,可以通过将资源文件添加到项目中来方便地访问和管理这些资源。这些资源文件可以位于qrc文件所在目录的同级或其子目录下
- 在构建程序的过程中,Qt会把资源文件的二进制数据转成cpp代码,编译到exe中。从而使依赖的资源变得"路径无关"(Qt在编译项目的时候,就会根据qrc中描述的图片信息,找到图片内容,并且提取出图片中的二进制数据,把这些二进制数据转换成c++代码最终编译到exe中)
qrc缺点:
- 无法导入太大的资源文件(比如几个GB的视频文件,qrc不可以)
- 在上面代码的基础上创建一个qrc文件(文件名不带中文和特殊符号)
.qrc后缀可加可不加
创建完成页面如下:
- 将图片导入到qrc文件中
在qrc编辑器中,添加前缀(Prefix):
前缀设置成 / 即可,所谓前缀可以理解成虚拟目录,这个目录没有在你电脑上真实存在,而是Qt自己抽象出来的(qrc机制的本质就是把图片的二进制数据转化为C++代码,最终就会在代码中看到很大的char数组,里面就是图片的二进制数据)
将图片导入到资源文件中:资源编辑器中,点击add Files 添加资源文件。此处我们需要添加的是Qt.png)注意:添加的文件必须是在qrc文件的同级目录,或者同级目录的子目录中。因此我们需要把之前D盘中的Qt.png复制到上述目录中
qrc路径的访问规则:
• 使用
:作为开头表示从qrc中读取资源•
/是上面配置的前缀• Qt.png 是资源的名称
运行程序
qrc中导入的图片资源会被转换成这个qrc_resource.cpp这个C++代码
.cpp文件中保存的是图片里每一个字节的数据 (当Qt项目进行编译时,这个cpp文件也就被一起编译在exe文件中,当exe程序执行的时候。上述图片数据就被加载到内存之中)
windowOpacity
- windowOpacity:设置窗口透明度
| API | 说明 |
|---|---|
| windowOpacity() | 获取到控件的不透明数值,返回float----取值为0.0->1.0。其中0.0表示全透明,1.0表示完全不透明 |
| setWindowOpacity(float n) | 设置控件的不透明数值 |
- 创建两个按钮,一个按钮增加透明度,一个按钮减少(objectName:pushButton_add、pushButton_sub)
- 定义槽函数
cpp
void Widget::on_pushButton_add_clicked()
{
float opacity = this->windowOpacity();
if(opacity >= 1.0)
return;
qDebug() << opacity;
opacity += 0.1;
this->setWindowOpacity(opacity);
}
void Widget::on_pushButton_sub_clicked()
{
float opacity = this->windowOpacity();
if(opacity <= 0.0)
return;
qDebug() << opacity;
opacity -= 0.1;
this->setWindowOpacity(opacity);
}
按-的按钮,窗口变透明,我们发现打印日志并不是按照每次减0.1来减少的(原因:浮点数在内存中的存储方式)
cursor
| API | 说明 |
|---|---|
| cursor() | 获取到当前widget的cursor属性,返回QCursor对象。当鼠标悬停在该widget上时,就会显示出对应的形状。 |
| setCursor(const QCursor& cursor) | 设置该widget光标的形状,仅在鼠标停留在该widget上时生效 |
| QGuiApplication::setOverrideCursor(const QCursor& cursor) | 设置全局光标的形状,对整个程序中的所有widget都会生效。覆盖上面的setCursor设置的内容 |
- cursor()、setCursor(const QCursor& cursor)是Widget级别的,同一个界面中,不同控件可以设置成不同的光标
- QGuiApplication::setOverrideCursor(const QCursor& cursor):设置全局光标,程序内的全局,不是系统级别的全局
- 在Qt Designer中设置按钮的光标:
- 创建一个按钮,在侧边栏的属性区域修改按钮光标(内置光标)

- 通过代码来修改按钮光标

Qt内置光标
- 自定义鼠标光标
- 准备一张图片(Qt.png),把图片导入到项目中(qrc),在代码访问到这张图片,基于图片构造出光标对象并设置
- qrc和上面一样的操作,这里不再演示

- 访问这个图片(使用QPixmap),图片是一个范围,不是一个点,当鼠标点击时,相当于图片的左上角进行点击。如果想要修改点击的位置,可以在
QCursor cursor(pixmap)传入一个像素坐标:QCursor cursor(pixmap, 10, 10),(10, 10)即热点所在位置
cpp
QPixmap pixmap(":/Qt.png");
QCursor cursor(pixmap);
cpp
QPixmap pixmap(":/Qt.png");
QCursor cursor(pixmap, 10, 10);
this->setCursor(cursor);
- 如果图片比较大,我们可以使用pixmap的scaled来进行缩放(注意:缩放不是修改图片本身,而是返回一个新的图片对象副本)
cpp
pixmap = pixmap.scaled(100, 100); // 放大
font
| API | 说明 |
|---|---|
| font() | 获取当前widget的字体信息,返回QFont对象 |
| setFont(const QFont& font) | 设置当前widget的字体信息 |
- 设置字体属性(在右侧的属性编辑区,设置该label的font相关属性)

- 在代码中设置字体属性
- 在界面中创建label,objectName 使用默认的label 即可
cpp
QLabel* label = new QLabel(this);
label->setText("这是一个文本");
//创造字体对象
QFont font;
font.setFamily("仿宋");
font.setPixelSize(30);
font.setBold(true);
font.setItalic(true);
font.setUnderline(true);
font.setStrikeOut(true);
label->setFont(font);
toolTip
- GUI程序界面比较复杂,按钮较多,当你把鼠标悬停到这个控件上时就能弹出提示
| API | 说明 |
|---|---|
| setToolTip | 设置toolTip,鼠标悬停在该widget上时会有提示说明 |
| setToolTipDuring | 设置toolTip提示的时间,单位ms;时间到后toolTip自动消失 |
- 设置按钮的toolTip
- 在界面上拖放两个按钮:objectName 设置为pushButton_yes 和pushButton_no
cpp
ui->pushButton_yes->setToolTip("这是yes按钮");
ui->pushButton_yes->setToolTipDuration(3000);
ui->pushButton_no->setToolTip("这是no按钮");
ui->pushButton_no->setToolTipDuration(3000);
focusPolicy
- 设置控件获取到焦点的策略。比如某个控件能否用鼠标选中 或者能否通过tab键选中
- 所谓"焦点"指的就是能选中这个元素,接下来的操作(比如键盘操作)就都是针对该焦点元素进行的了。这个对于输⼊框、单选框、复选框等控件非常有用
| API | 说明 |
|---|---|
| focusPolicy() | 获取该widget的focusPolicy,返回Qt::FocusPolicy |
| setFocusPolicy(Qt::FocusPolicy policy) | 设置widget的focusPolicy |
Qt::FocusPolicy 是一个枚举类型。取值如下:
• Qt::NoFocus:控件不会接收键盘焦点
• Qt::TabFocus:控件可以通过Tab键接收焦点
• Qt::ClickFocus:控件在鼠标点击时接收焦点
• Qt::StrongFocus:控件可以通过Tab键和鼠标点击接收焦点(默认值)
• Qt::WheelFocus:类似于Qt::StrongFocus ,同时控件也通过鼠标滚轮获取到焦点(新增的选项,一般很少使用)
- 理解不同的focusPolicy
-
在界面上创建四个单行输入框(Line Edit)
-
修改四个输入框的focusPolicy 属性为Qt::StrongFocus (默认取值,一般不用额外修改)
-
修改第二个输入框的focusPolicy 为Qt::NoFocus ,则第二个输入框不会被tab/鼠标左键选中,此时这个输入框也就无法输入内容了

-
修改第二个输入框focusPolicy 为Qt::TabFocus ,则只能通过tab选中,无法通过鼠标选中

-
修改第二个输入框focusPolicy 为Qt::ClickFocus ,则只能通过鼠标选中,无法通过tab选中

styleSheet
- 通过CSS设置widget的样式
- CSS (Cascading Style Sheets层叠样式表)本身属于网页前端技术。主要就是用来描述界面的样式。
- 所谓"样式":包括不限于大小、位置、颜色、间距、字体、背景、边框等。我们平时看到的丰富多彩的网页就都会用到大量的CSS
- CSS中可以设置的样式属性非常多。基于这些属性Qt只能支持其中一部分,称为QSS(Qt Style Sheet)。具体的支持情况可以参考Qt文档中"Qt Style Sheets Reference"章节
- 设置文本样式
- 在界面上创建label

- 右侧的styleSheet属性,设置样式
- 此处的语法格式同CSS使用键值对的方式设置样式。其中键和值之间使用
:分割;键值对之间使用;分割


- 通过代码来设置样式(实现一个"夜间模式"功能)
- 日间模式:文字是黑色,背景是白色
- 夜间模式:文字是白色,背景是黑色
- 在界面上创建一个多行输入框(Text Edit或者plain Text Edit)和两个按钮:objectName分别为pushButton_light 和pushButton_dark
- 编写按钮的槽函数
cpp
void Widget::on_pushButton_light_clicked()
{
//日间
//设置窗口样式
this->setStyleSheet("background-color:white;");
//设置输入框样式
ui->plainTextEdit->setStyleSheet("background-color:white; color: black;");
//设置按钮样式
ui->pushButton_light->setStyleSheet("color: black;");
ui->pushButton_dark->setStyleSheet("color: black;");
}
void Widget::on_pushButton_dark_clicked()
{
//夜间
//设置窗口样式
this->setStyleSheet("background-color:black;");
//设置输入框样式
ui->plainTextEdit->setStyleSheet("background-color:black; color: white;");
//设置按钮样式
ui->pushButton_light->setStyleSheet("color: white;");
ui->pushButton_dark->setStyleSheet("color: white;");
}

关于计算机中的颜色表示:
- 计算机中使用"像素"表示屏幕上的一个基本单位(也就是一个发亮的光点) 每个光点都使用三个字节表示颜色,分别是R(red),G(green),B(blue)一个字节表示(取值范围是0-255,或者0x00-0xFF)
- 混合三种不同颜色的数值比例就能搭配出千千万万的颜色出来
- rgb(255, 0, 0) 或者#FF0000 或者#F00 表示纯红色
- rgb(0, 255, 0) 或者#00FF00 或者#0F0 表示纯绿色
- rgb(0, 0, 255) 或者#0000FF或者#00F 表示纯蓝色
- rgb(255, 255, 255) 或者#FFFFFF 或者#FFF 表示纯白色
- rgb(0, 0, 0) 或者#000000 或者#000 表示纯黑色
- 当然,上述规则只是针对一般的程序而言是这么设定的。实际的显示器可能有8bit色深或者10bit色深等,实际情况会更加复杂












