一、控件概述
Widget 是 Qt 中的核⼼概念. 英⽂原义是 "⼩部件", 我们此处也把它翻译为 "控件" .控件是构成⼀个图形化界⾯的基本要素.
上述示例中的 按钮、树形视图、列表视图、下拉框等等都可以称作 “控件”。

这些都是Qt给我们内置的控件,当然如果这些空间不能把满足需求的时候,我们也可对现有控件做 出扩展, 或者手搓出新的控件。
二、QWidget 控件属性
在Qt中,使用QWidget类表示"控件"像按钮,视图,输入框,滚动条等具体的控件类,都是继承自QWidget。
可以说,QWidget中就包含了Qt整个控件体系中,通用的部分。
在Qt Designer中,随便拖一个控件过来,选中该控件,即可在右下方看到QWidget中的属性。
这些属性,我们还能在这里进行编译。
enabled 属性
属性 | 作用 |
enabled |
设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤
|
API | 说明 |
isEnabled()
|
获取到控件的可⽤状态
|
setEnabled
|
设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤
|
示例:将一个按钮设置为禁用状态
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->pushButton->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
qDebug() << "hello Qt";
}
可以看到按钮处于灰色状态,无法点击。
示例:使用另一个按钮将第一个按钮随意设置状态
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
qDebug() << "hello Qt";
}
void Widget::on_enable_pushButton_clicked()
{
// 获取第一个按钮的可用状态
bool enable = ui->pushButton->isEnabled();
if(enable)
ui->pushButton->setEnabled(false);
else
ui->pushButton->setEnabled(true);
}
geometry 属性
位置和尺寸. 其实是四个属性的统称:x:横坐标y:纵坐标width:宽度height:高度
但是实际开发中, 我们并不会直接使⽤这⼏个属性, ⽽是通过⼀系列封装的⽅法来获取/修改
API | 说明 |
geometry()
|
获取到控件的位置和尺⼨. 返回结果是⼀个 QRect, 包含了 x, y, width, height. 其中 x, y 是左上⻆的坐标
|
setGeometry(QRect)
setGeometry(int x, int y, int width, int height)
|
设置控件的位置和尺⼨. 可以直接设置⼀个 QRect, 也可以分四个属性单独设置
|
特别说明:QRect表示一个矩形,QPoint表示一个点;move只是修改位置,setGeometry既可以修改位置,又可以修改尺寸。
示例:使用 上下左右四个按钮控制 target 按钮的移动
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_up_clicked()
{
// 获取到 target 本身的 geometry
QRect rect = ui->pushButton_target->geometry();
qDebug() << rect;
// rect.setY(rect.y()-5);
// ui->pushButton_target->setGeometry(rect);
ui->pushButton_target->setGeometry(rect.x(),rect.y()-5,rect.width(),rect.height());
}
void Widget::on_pushButton_down_clicked()
{
QRect rect = ui->pushButton_target->geometry();
qDebug() << rect;
// rect.setY(rect.y()+5);
// ui->pushButton_target->setGeometry(rect);
ui->pushButton_target->setGeometry(rect.x(),rect.y()+5,rect.width(),rect.height());
}
void Widget::on_pushButton_left_clicked()
{
QRect rect = ui->pushButton_target->geometry();
qDebug() << rect;
// rect.setX(rect.x()-5);
// ui->pushButton_target->setGeometry(rect);
ui->pushButton_target->setGeometry(rect.x()-5,rect.y(),rect.width(),rect.height());
}
void Widget::on_pushButton_right_clicked()
{
QRect rect = ui->pushButton_target->geometry();
qDebug() << rect;
// rect.setX(rect.x()+5);
// ui->pushButton_target->setGeometry(rect);
ui->pushButton_target->setGeometry(rect.x()+5,rect.y(),rect.width(),rect.height());
}
送你一份 表白成功率100% 的表白小程序,嘿嘿嘿!!!
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置随机数种子
srand(time(0));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_no_clicked()
{
// 有了 press, click 没有用了
}
void Widget::on_pushButton_yes_clicked()
{
ui->label->setText("I love you too, mua~ please");
}
void Widget::on_pushButton_no_pressed()
{
// 挪走这个按钮,随机位置——新的位置
// 获取到当前程序窗口的尺寸
int width = this->geometry().width();
int height = this->geometry().height();
// 重新生成按钮的位置
int x = rand() % width;
int y = rand() % height;
// 移动按钮的位置
QRect rect = ui->pushButton_no->geometry();
ui->pushButton_no->setGeometry(x, y, rect.width()-5, rect.height()-5);
QRect rect_yes = ui->pushButton_yes->geometry();
ui->pushButton_yes->setGeometry(rect_yes.x()-10,rect_yes.y()-5, rect_yes.width()+500, rect_yes.height()+300);
}
WindowFrame
如果 widget 作为⼀个窗⼝ (带有标题栏, 最小化, 最大化, 关闭按钮), 那么在计算尺寸和坐标的时候就有两种算法. 包含 window frame 和 不包含 window frame。其中 x(), y(), frameGeometry(), pos(), move() 都是按照包含 window frame 的⽅式来计算的。其中 geometry(), width(), height(), rect(), size() 则是按照不包含 window frame 的⽅式来计算的
在Qt中,关于位置尺寸,提供了很多的API。
有的API的位置信息是以 Widget 本体左上角为原点的(不考虑Window frame),eg: geometry(), setGeometry()。
有的API的位置信息是以 window frame 左上角为原点的。eg: frameGeometry(), setFrameGeometry()。
一些 API :
API | 说明 |
x() |
获取横坐标
计算时包含 window frame
|
y() |
获取纵坐标
计算时包含 window frame
|
pos() | 返回 QPoint 对象, ⾥⾯包含 x(), y(), setX(), setY() 等⽅法.
计算时包含 window frame
|
frameSize()
|
返回 QSize 对象, ⾥⾯包含 width(), height(), setWidth(), setHeight() 等⽅法.
计算时包含 window frame
|
frameGeometry()
|
返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取 x, y, width, size.
计算时包含 window frame 对象.
|
width()
|
获取宽度
计算时不包含 window frame
|
height()
|
获取⾼度
计算时不包含 window frame
|
size()
|
返回 QSize 对象, ⾥⾯包含 width(), height(), setWidth(), setHeight() 等⽅法.
计算时不包含 window frame
|
rect()
|
返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取并设置 x,
y, width, size.
计算时不包含 window frame 对象
|
geometry()
|
返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取 x, y,
width, size.
计算时不包含 window frame 对象
|
setGeometry()
|
直接设置窗⼝的位置和尺⼨. 可以设置 x, y, width, height, 或者 QRect 对象.
计算时不包含 window frame 对象
|
示例:查看 geometry() 和 Framegeometry() 的区别
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 当前代码是放到构造函数中 此时这个Widget对象正在构造,还没有被加入到window frame中,因此,此时还看不到window frame的影响.
QRect rect1 = this->geometry();
QRect rect2 = this->frameGeometry();
qDebug() << rect1;
qDebug() << rect2;
}
Widget::~Widget()
{
delete ui;
}
所以,通过一个按钮来实现这个示例:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// QRect rect1 = this->geometry();
// QRect rect2 = this->frameGeometry();
// qDebug() << rect1;
// qDebug() << rect2;
QPushButton* button = new QPushButton(this);
button->setText("按钮");
button->move(100,100);
connect(button, &QPushButton::clicked, this, &Widget::handle);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
QRect rect1 = this->geometry();
QRect rect2 = this->frameGeometry();
qDebug() << rect1;
qDebug() << rect2;
}
windowTitle 属性
窗口标题
API | 说明 |
windowTitle()
|
获取到控件的窗⼝标题
|
setWindowTitle(const QString& title)
|
设置控件的窗⼝标题.
|
注意! 上述设置操作针对不同的 widget 可能会有不同的⾏为.
如果是顶层 widget (独⽴窗⼝), 这个操作才会有效.如果是⼦ widget, 这个操作⽆任何效果
示例:设置窗口标题
windowlcon 属性
窗口图标
API | 说明 |
windowIcon()
|
获取到控件的窗⼝图标. 返回 QIcon 对象
|
setWindowIcon(const QIcon& icon)
|
设置控件的窗⼝图标.
|
同 windowTitle, 上述操作仅针对顶层 widget 有效
既然要设置控件的窗口图标,那么就有以下几个注意的点。
- 之前推荐使用堆来创建对象,主要是因为要确保当前的控件的生命周期是足够的,要通过Qt对象树来释放对象,
- Qlcon自身是一个比较小的对象,创建出来之后,就是要设置到某个QWidget里面,Qlcon对象本身释放不释放,不影响图标最终的显示
- Qlcon也不支持对像树.无法给他执行父对象.
- Qt中封装的这些类,都会有同名的头文件。
示例:设置窗口图标
设置窗口图标为:
#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:/aba_abab.png");
this->setWindowIcon(icon);
}
Widget::~Widget()
{
delete ui;
}
实际开发中, 我们⼀般不会在代码中通过绝对路径引⼊图⽚. 因为我们⽆法保证程序发布后, ⽤ ⼾的电脑上也有同样的路径。
如果使用相对路径, 则需要确保代码中的相对路径写法和图片实际所在的路径匹配 (⽐如代码中写作 "./image/rose.jpg", 就需要在当前⼯作⽬录中创建 image ⽬录, 并把 rose.jpg 放进去)——这就需要 qrc 机制了
qrc 文件管理资源
qrc机制就是从根本上解决上述的两个问题:
1.确保你的图片所在的路径在目标用户机器上存在
2.确保你的图片不会被用户搞没了~~
给Qt项目引入一个额外的xml文件(后缀名使用.qrc表示),在这个xml中把要使用的图片资源给导入进来,并且在xml中进行记录。Qt在编译项目的时候就会根据qC中描述的图片信息,找到图片内容,并且提取出图片的二进制数据,把这些二进制数据转成C++代码.最终编译到exe里。
qrc缺点:无法导入太大的资源文件。比如搞几个GB这种视频文件,qrc无能为力了
qrc 使用方式:1.在项目中创建一个qrc文件,文件名不要带中文和特殊符号。
之后,下一步:文件名随便起,但是不要带中文和特殊符号。
1)先创建一个"前缀”(Prefix)
所谓的"前缀”可以理解成虚拟的目录,这个目录没有在你的电脑上真实存在,是Qt自己抽象出来的
qrc机制本质上就是把图片的二进制数据,转成C++代码.(最终就会在代码中看到很大的char数组,里面就是图片的二进制数据),为了方便Qt代码中访问到这个图片,Qt就自己抽象出了虚拟的目录。
2)把刚才使用rose.jpg这个图片给导入到资源文件中.
QIcon icon(":/aba_abab.png"); 当代码中需要访问 qrc 中管理的文件时,就需要在路径上带有:前缀
qrc中导入的图片资源,就会被转成这个qrc_resource.cpp这个c++代码
这里的字节内容就是这个图片里的每个字节的数据
当Qt项目进行编译的时候这个cpp文件就被一起编译到了exe中,当exe程序运行的时候,上述图片的数据也就被加载到内存中了。
windowOpacity 属性
透明度属性
API | 说明 |
windowOpacity()
|
获取到控件的不透明数值. 返回 float, 取值为 0.0 -> 1.0 其中 0.0 表⽰全透明,1.0 表示完全不透明.
|
setWindowOpacity(float n)
|
设置控件的不透明数值.
|
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_light_clicked()
{
// 设置界面为 日间模式
float opacity = this->windowOpacity();
if(opacity >= 1.0)
return;
qDebug() << opacity;
opacity += 0.1; // 不透明度 + 0.1
this->setWindowOpacity(opacity);
}
void Widget::on_pushButton_night_clicked()
{
// 设置界面为 黑夜模式
float opacity = this->windowOpacity();
if(opacity <= 0.0)
return;
qDebug() << opacity;
opacity -= 0.1; // 不透明度 - 0.1
this->setWindowOpacity(opacity);
}
降低透明度,结果示例如下:
cursor 属性
改变光标形状
API | 说明 |
cursor()
|
获取到当前 widget 的 cursor 属性, 返回QCursor 对象,当⿏标悬停在该 widget 上时,就会显⽰出对应的形状。
|
setCursor(const QCursor& cursor)
|
设置该 widget 光标的形状. 仅在⿏标停留在该 widget 上时⽣效
|
QGuiApplication::setOverrideCursor(const QCursor& cursor)
|
设置全局光标的形状。对整个程序中的所有 widget 都会⽣效,覆盖上⾯的 setCursor 设置的内容。
|
示例:在 Qt Designer 中设置按钮的光标
直接在 UI 界面上设置。
使用代码设置
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QCursor cursor(Qt::WaitCursor);
ui->pushButton->setCursor(cursor);
}
Widget::~Widget()
{
delete ui;
}
Ctrl,按下 WaitCursor,会有一系列其他类型光标
当然也可以使用我们的图片来进行光标的设置。
注意:默认情况下,鼠标点击时,相当于 图片的左上角进行点击
第一步,先准备一个图片,把图导入到项目中(qc管理),在代码中访问到这个图片,基于这个图片构造出光标对像并设置。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// QCursor cursor(Qt::WaitCursor);
// ui->pushButton->setCursor(cursor);
// 访问到图片文件
QPixmap pixmap(":/sing.png");
pixmap = pixmap.scaled(100,100); // 对图片进行缩放
// 构造光标对象
QCursor cursor(pixmap, 10,10); //相位于图片左上角10,10位置处为焦点
// 将光标设置进去
this->setCursor(cursor);
}
Widget::~Widget()
{
delete ui;
}
front 属性
修改字体信息
API | 说明 |
font()
|
获取当前 widget 的字体信息. 返回 QFont 对象
|
setFont(const QFont& font)
|
设置当前 widget 的字体信息
|
关于 QFront 的一些属性
属性 | 说明 |
family
|
字体家族. ⽐如 "楷体", "宋体", "微软雅⿊" 等
|
pointSize
|
字体⼤⼩
|
weight
|
字体粗细. 以数值⽅式表⽰粗细程度取值范围为 [0, 99], 数值越⼤, 越粗.
|
bold
|
是否加粗. 设置为 true, 相当于 weight 为 75. 设置为 false 相当于
weight 为 50
|
italic
|
是否倾斜
|
underline
|
是否带有下划线
|
strikeOut
|
是否带有删除线
|
示例:设置 字体属性形式
直接在 UI 界面操作设置
通过属性编辑这样的方式虽然能够快速方便的修改文字相关的属性但是还不够灵活,如果程序运行过程中,需要修改文字相关的属性就需要通过代码来操作了,
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 构造 Label标签对象
QLabel* label = new QLabel(this);
label->setText("我是一个 Label 标签");
// 创建字体对象
QFont font;
font.setFamily("微软雅黑");
font.setPixelSize(40);
font.setBold(true);
font.setItalic(true);
font.setUnderline(true);
font.setStrikeOut(true);
// 将字体对象设置进 label 中
label->setFont(font);
}
Widget::~Widget()
{
delete ui;
}
toolTip 属性
鼠标提示说明
API | 说明 |
setToolTip
|
设置 toolTip.
⿏标悬停在该 widget 上时会有提⽰说明
|
setToolTipDuring
|
设置 toolTip 提⽰的时间. 单位 ms.
时间到后 toolTip ⾃动消失.
|
设置按钮的 toolTip
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置这两个按钮的 toolTip
ui->pushButton_yes->setToolTip("这时一个yes按钮");
ui->pushButton_yes->setToolTipDuration(3000); // 提示3s后消失
ui->pushButton_no->setToolTip("这是一个 no 按钮");
ui->pushButton_no->setToolTipDuration(7000);
}
Widget::~Widget()
{
delete ui;
}
focusPolicy 属性
设置控件获取焦点的策略。
API | 说明 |
focusPolicy()
|
获取该 widget 的 focusPolicy, 返回 Qt::FocusPolicy
|
setFocusPolicy(Qt::FocusPolicypolicy)
|
设置 widget 的 focusPolicy
|
Qt::FocusPolicy 是⼀个枚举类型. 取值如下:
- Qt::NoFocus :控件不会接收键盘焦点
- Qt::TabFocus :控件可以通过Tab键接收焦点
- Qt::ClickFocus :控件在⿏标点击时接收焦点
- Qt::StrongFocus :控件可以通过Tab键和⿏标点击接收焦点 (默认值)
- Qt::WheelFocus : 类似于 Qt::StrongFocus , 同时控件也通过⿏标滚轮获取到焦点 (新增的选项, ⼀般很少使用)

运行程序查看具体情况。
styleSheet 属性
通过 CSS 设置 widget 的样式
示例:通过 styleSheet 属性初步演示
和CSS类似.QSS设置的样式也是键值对的格式。键和值之间使用:分隔
键值对和键值对之间使用;分隔。
这些 font- 属性,Qt 的文档中会有更为详细的介绍。
示例:设置日间模式和夜间模式
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_night_clicked()
{
// 夜间模式:文字是白色,背景是黑色
this->setStyleSheet("background-color: black;");
// 设置输入框的样式
ui->plainTextEdit->setStyleSheet("background-color: black; color: white;");
// 设置按钮的样式
ui->pushButton_bright->setStyleSheet("color: white;");
ui->pushButton_night->setStyleSheet("color: white;");
}
void Widget::on_pushButton_bright_clicked()
{
// 日间模式:文字是黑色,背景是白色
this->setStyleSheet("background-color: white;");
// 设置输入框的样式
ui->plainTextEdit->setStyleSheet("background-color: white; color: black;");
// 设置按钮的样式
ui->pushButton_bright->setStyleSheet("color: black;");
ui->pushButton_night->setStyleSheet("color: black;");
}
不过这样的颜色看起来太奇怪了,给它设置的漂亮一点
首先需要认识计算机中,颜色是怎样表示的。并且CSS/QSS中是可以直接使用单词来设置颜色的.white,black,red,green,blue,yellow…
在计算机中,使用RGB的方式来表示颜色
QQ截图,内置了取色器。
void Widget::on_pushButton_night_clicked()
{
// 夜间模式:文字是白色,背景是黑色
this->setStyleSheet("background-color: rgb(39,70,117);");
// 设置输入框的样式
ui->plainTextEdit->setStyleSheet("background-color: black; color: white;");
// 设置按钮的样式
ui->pushButton_bright->setStyleSheet("color: white;");
ui->pushButton_night->setStyleSheet("color: white;");
}
void Widget::on_pushButton_bright_clicked()
{
// 日间模式:文字是黑色,背景是白色
this->setStyleSheet("background-color: rgb(3,70,149);");
// 设置输入框的样式
ui->plainTextEdit->setStyleSheet("background-color: white; color: black;");
// 设置按钮的样式
ui->pushButton_bright->setStyleSheet("color: black;");
ui->pushButton_night->setStyleSheet("color: black;");
}