Widget是Qt中的核心概念英文原义是"小部件",我们此处也把它翻译为"控件" .
控件是构成一个图形化界面的基本要素.
像上述示例中的,按钮,列表视图,树形视图,单行输入框,多行输入框,滚动条,下拉框等,都可以称为"控件".
Qt作为一个成熟的GUI开发框架,内置了大量的常用控件.这一点在Qt Designer中就可以看到端倪.
并且Qt也提供了"自定义控件"的能力,可以让程序员在现有控件不能满足需求的时候,对现有控件做出扩展,或者手搓出新的控件.
综上,学习Qt,其中一个很重要的任务就是熟悉并掌握Qt内置的常用控件. 这些控件对于我们快速开发出符合需求的界面,是至关重要的.
关于控件体系的发展
控件是GUI开发中的通用概念.不仅仅局限在Qt中.
第一阶段:
完全没有控件.此时需要通过一些绘图 API手动的绘制出按钮或者输入框等内容,代码编写繁琐.
例如文曲星的Lava平台开发.
第二阶段: .
只包含粗略的控件.只是提供了按钮,输入框,单选框,复选框等最常用的控件.
例如html的原生控件.
第三阶段:
更完整的控件体系,基本可以覆盖到GUI开发中的大部分场景.
例如早期的MFC, VB, C++ Builder, Qt, Delphi,后来的Android SDK, Java FX,前端的各种UI库等.
在Qt中,使用QWidget类表示"控件".像按钮,视图,输入框,滚动条等具体的控件类,都是继承自QWidget.
可以说,QWidget中就包含了Qt整个控件体系中,通用的部分.
在Qt Designer中,随便拖一个控件过来,选中该控件,即可在右下方看到QWidget中的属性
在Qt Designer中,随便拖- -个控件过来,选中该控件,即可在右下方看到QWidget中的属性
这些属性既可以通过QtDesigner会直接修改,也可以通过代码的方式修改.
这些属性的具体含义,在Qt Assistant中均有详细介绍.
属性 | 作用 |
---|---|
enabled | 设置控件是否可使用. true 表示可用,false 表示禁用. |
geometry | 位置和尺寸.包含x, y, width, height四个部分.其中坐标是以父元素为参考进行设置的. |
windowTitle | 设置widget标题 |
windowlcon | 设置widget图标 |
windowOpacity | 设置widget透明度 |
cursor | 鼠标悬停时显示的图标形状.是普通箭头,还是沙漏,还是十字等形状.在Qt Designer界面中可以清楚看到可选项. |
font | 字体相关属性.涉及到字体家族,字体大小,粗体,斜体,下划线等等样式. |
toolTip | 鼠标悬停在widget.上会在状态栏中显示的提示信息. |
toolTipDuring | toolTip显示的持续时间. |
statusTip | Widget状态发生改变时显示的提示信息(比如按钮被按下等). |
whatsThis | 允许使用CSS来设置widget中的样式. |
styleSheet | 允许使用CSS来设置widget中的样式.Qt中支持的样式非常丰富,对于前端开发人员上手是非常友好的. |
focusPolicy | focusPolicy该widget如何获取到焦点. ●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 | 指定窗口是否具有"模态"行为. |
sizelncrement | 拖动窗口大小时的增量单位. |
baseSize | 窗口的基础大小,用来搭配sizelncrement调整组件尺寸是计算组件应该调整到的合适的值. |
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的可访问名称.这个名称可以被辅助技术(像屏幕阅读器)获取到.设置widget的可访问名称.这个名称可以被辅助技术(像屏幕阅读器)获取到.这个属性用于实现无障碍程序的场景中(也就是给盲人写的程序).其实盲人也是可以使用电脑和手机的.甚至盲人还能成为程序猿.参见https://www.bilibili.com/video/BV1954y1d7z9 |
accessibleDescription | 设 置widget的详细描述.作用同accessibleName |
inputMethodHints | 针对输入框有效,用来提示用户当前能输入的合法数据的格式.比如只能输入数字,只能输入日期等. |
接下来我们会介绍其中一些比较重要比较常用的属性,并附有代码示例.
注意:本章节的每个代码示例都是创建了单独的Qt项目.省略了创建项目的具体步骤.
示例:使用代码创建一个禁用状态的按钮
运行程序,可以看到按钮处于灰色状态,无法被点击
在 ui 编辑界面右下角可以设置按钮的初始状态
geometry 意思是几何。这里表示位置和尺寸,其实是四个属性的统称
实际开发中,我们并不会直接使用这几个属性,而是通过一系列封装的方法来获取/修改。
对于 Qt 的坐标系,不要忘记是一个 “左手坐标系”,其中坐标系的原点是当前父元素的左上角。
QRect 表示矩形
代码示例 1 :通过按钮控制另外一个按钮的大小。
点击方向键即可控制按钮的大小。按下下方的四个按钮,就会控制 target 的左上角的位置,对应的按钮整个尺寸也会发生改变。
上述代码中我们是直接设置的 QRect 中的 x ,y 。实际上 QRect 内部是存储了左上和右下两个点的坐标,再通过这两个点的坐标差值计算长宽。
单纯修改左上坐标就会引起整个矩形的长宽发生改变。
代码示例 2 : 控制按钮让另外一个按钮移动
如果想让按钮发生移动可以使用下列代码
此时就可以通过下面四个按钮让上面的按钮移动。
如果widget作为一个窗口(带有标题栏,最小化,最大化,关闭按钮),那么在计算尺寸和坐标的 时候就有两种算法.包含window frame和不包含window frame. 其中x(), y(), frameGeometry(), pos(),
move()都是按照包含window frame的方式来计算的. 其中geometry(), width(), height(),
rect(), size()则是按照不包含window frame的方式来计算的. 当然,如果一个不是作为窗口的widget,上述两类方式得到的结果是一致的.
代码示例 :对比 geometry 和 frame geometry 的区别
注意,如果直接在构造函数中使用geimetry和frame geometry,那么得到的窗口大小是没有区别的,因为此时 Widget 对象正在构造,还没有被加入到 window frame 中
我们设置一个按钮,然后点击按钮才触发槽函数,把这两个 API放在槽函数里面。
可以看到窗口大小的区别。
如果我们改成获取按钮的大小,可以看到是一样的,因为按钮并不是一个窗口。
注意:上述设置操作针对不同的 widget 会有不同的行为。如果是顶层的 widget (独立窗口)这个操作才有效。如果是子 widget ,这个操作无任何效果,且不会报错。
同windowTitle, .上述操作仅针对顶层widget有效.
代码示例 1 :设置窗口图标
icon 可以去阿里巴巴矢量图这个网站去下载
先在 D 盘中放一个图片,名字为 txt.png
修改 widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建图标对象
QIcon icon("d:/txt.png");
//设置图标
this->setWindowIcon(icon);
}
Widget::~Widget()
{
delete ui;
}
运行程序,可以看到窗口图标已经变为上述图片
程序在任务栏的图标也发生改变
实际开发中,我们一般不会在代码中通过绝对路径引入图片.因为我们无法保证程序发布后,用
户的电脑上也有同样的路径.
如果使用相对路径,则需要确保代码中的相对路径写法和图片实际所在的路径匹配(比如代码
中写作"./image/txt.png",就需要在当前工作目录中创建image目录,并把txt.png放进去).
绝对路径:以盘符(windows)或者以/ (Linux) 开头的路径.
相对路径:以。(表示当前路径)或者以.。(表示当前路径.上级路径)开头的路径.其中|。经常也
会省略.相对路径的前提是需要明确"当前工作目录".
对于Qt程序来说,当前工作目录可能是变化的.比如通过Qt Creator运行的程序,当前工作目录是项目的构建目录;直接双击exe运行,工作目录则是exe所在目录.
所谓构建目录,是和Qt项目并列的,专门用来放生成的临时文件和最终exe的目录.
注意,上述构建目录,是随时可删除的.比如点击菜单栏中的"构建" -> “清理项目” ,就会把这个目录中的内容清空掉.
因此如果我们把图片文件放到构建目录中,可能在不小心删除后就丢失了.我们还是希望能够把图片和源代码放到一起,并且使我们的程序无论拷贝到任何位置中都能正确使用图片.
Qt使用qrc机制帮我们自动完成了.上述工作,更方便的来管理项目依赖的静态资源.
qrc文件是一种XML格式的资源配置文件,它用XML记录硬盘上的文件和对应的随意指定的资
源名称.应用程序通过资源名称来访问这些资源.
在Qt开发中,可以通过将资源文件添加到项目中来方便地访问和管理这些资源.这些资源文件
可以位于qrc文件所在目录的同级或其子目录下.
在构建程序的过程中,Qt会把资源文件的二进制数据转成cpp代码,编译到exe中.从而使依
赖的资源变得"路径无关".
这种资源管理机制并非Qt独有,很多开发框架都有类似的机制.例如Android的Resources
和AssetManager也是类似的效果.
代码示例 2 :通过 qrc 管理图片作为图标
右键项目,创建一个Qt Resource File (qrc文件),文件名随意起(不要带中文),此处叫做
resource.qrc .
所谓的前缀,可以理解成"目录" .这个前缀决定了后续我们如何在代码中访问资源.
在资源编辑器中,点击add Files 添加资源文件.此处我们需要添加的是 txt.png
注意:添加的文件必须是在qrc文件的同级目录,或者同级目录的子目录中.因此我们需要把之前D盘 中的 txt.png 复制到.上述目录中.
添加完毕后,可以在 资源编辑器 中查看添加好的文件
在代码中使用这个 icon
注意上述路径的访问规则:
需要确保代码中编写的路径和添加到qrc中资源的路径匹配.否则资源无法被访问(同时也不会有报错提示).
接下来,我们可以进入到项目的构建目录,可以看到,目录中多了一个 qrc_ resource.cpp 文件.直
接打开这个文件,可以看到类似如下代码: .
上述代码其实就是通过unsigned char数组,把 txt.png 中的每个字节都记录下来.这些代码会被编译到exe中.后续无论exe被复制到哪个目录下,都确保能够访问到该图片资源.
上述qrc这一套资源管理方案,优点和缺点都很明显.
优点:确保了图片,字体,声音等资源能够真正做到"目录无关",无论如何都不会出现资源丢失
的情况.
缺点:不适合管理体积大的资源.如果资源比较大(比如是几个MB的文件),或者资源特别多,
生成的最终的exe体积就会比较大,程序运行消耗的内存也会增大,程序编译的时间也会显著
增加.
代码示例:调整窗口透明度
在界面上拖放两个按钮,分别用来增加不透明度和减少不透明度.
objectName分别为pushButton_ add 和pushButton_ sub
编写wdiget.cpp,编写两个按钮的slot函数
点击pushButton_ sub会减少不透明度,也就是窗口越来越透明.
点击pushButton_ add会增加不透明度,窗口会逐渐恢复.
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);
}
执行程序,可以看到,点击了 sub 之后,窗口就变透明了。
同时控制台中也可以看到opacity数值的变化
注意: C++中float类型遵守IEEE 754标准,因此在进行运算的时候会有一定的精度误差.因此1 -
0.1的数值并非是0.9.
代码示例 1 :通过 Qt Designer 中设置按钮的光标
创建一个按钮,然后选中,可以直接在右下角的属性设置光标。
代码示例 2 : 通过代码设置按钮的光标
#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+左键点击Qt: :WaitCursor|跳转到源码即可看到.
代码示例 3 : 自定义鼠标光标
Qt 自带的鼠标光标也有限,但是允许我们自定义光标。以下面这个图片为例子。
创建 qrc 资源文件,添加前缀 / ,并加入该图片
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建一个位图对象,加载自定义光标图片
QPixmap pixmap(":/cursor.png");
//scaled 函数可以设置图片尺寸
pixmap = pixmap.scaled(64,64);
//创建 QCursor对象,并指定“热点”为(2,2)坐标位置
//所谓“热点” 就是鼠标点击时生效的位置
QCursor cursor(pixmap,2,2);
//设置光标
this->setCursor(cursor);
}
Widget::~Widget()
{
delete ui;
}
代码示例 1 : 在 Qt Designer 中设置字体属性
在界面上创建一个 label
在右侧的属性编辑区,设置该 label 的 font 的相关属性
在这里调整属性,可以实时看到文字的变化
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLabel *label = new QLabel(this);
label->setText("这是一段文本");
QFont font;//创建字体对象
font.setFamily("仿宋");//设置字体家族
font.setPointSize(20);//设置字体大小
font.setBold(true);//设置字体加粗
font.setItalic(true);//设置字体倾斜
font.setUnderline(true);//设置字体下划线
font.setStrikeOut(true);//设置字体删除线
label->setFont(font);//设置字体对象到 label 上
}
Widget::~Widget()
{
delete ui;
}
代码示例:设置 toolTip
在界面上拖放两个按钮. obj ectName设置为pushButton_ yes 和pushButton_ no
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->pushButton_yes->setToolTip("这是一个yes按钮");
ui->pushButton_yes->setToolTipDuration(3000);//设置为 3 秒
ui->pushButton_no->setToolTip("这是一个no按钮");
ui->pushButton_no->setToolTipDuration(3000);
}
Widget::~Widget()
{
delete ui;
}
也可以通过 ui 界面右边的属性直接设置 toolTip
把鼠标光标移到按钮上,即可看到提示
设置控件获取到焦点的策略.比如某个控件能否用鼠标选中或者能否通过tab键选中.
所谓"焦点",指的就是能选中这个元素.接下来的操作(比如键盘操作),就都是针对该焦点元素进行的了.这个对于输入框,单选框,复选框等控件非常有用的.
代码示例 :通过 Qt Designer 设置focusPolicy
在界面上创建四个单行输入框(Line Edit)
通过右下角的属性界面可直接设置每个输入框获取到焦点的策略
通过CSS设置widget的样式.
CSS (Cascading Style Sheets层叠样式表)本身属于网页前端技术.主要就是用来描述界面的 样式.
所谓"样式",包括不限于大小,位置,颜色,间距,字体,背景,边框等. 我们平时看到的丰富多彩的网页,就都会用到大量的CSS.
Qt虽然是做GUI开发,但实际上和网页前端有很多异曲同工之处.因此Qt也引入了对于CSS 的支持.
CSS中可以设置的样式属性非常多.基于这些属性Qt只能支持其中一部分,称为QSS (Qt Style Sheet). 具体的支持情况可以参考Qt文档中"Qt Style Sheets Reference"章节.
此处只是进行一个简单的演示.
代码示例 1 : 设置文本样式
在界面上创建 label
编辑右侧的styleSheet属性,设置样式
编辑完成样式之后,可以看到在Qt Designer中能够实时预览出效果.
此处的语法格式同CSS,使用键值对的方式设置样式.其中键和值之间使用:分割.键值对之间使用 ;分割. 另外, Qt
Designer只能对样式的基本格式进行校验,不能检测出哪些样式不被Qt支持.比如text- align: center
这样的文本居中操作,就无法支持.
运行程序,可以看到实际效果和预览效果基本一致.
代码示例 2 : 实现切换夜间模式
在界面上创建-一个多行输入框(Text Edit)和两个按钮.
objectName分别为pushButton light和pushButton dark
#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_light_clicked()
{
//设置窗口的样式
this->setStyleSheet("background-color: rgb(240,240,240);");
//设置输入框的样式
ui->textEdit->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->textEdit->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 或者#0FO 表示纯绿色.
rgb(0, 0,255)或者#0000FF或者#00F表示纯蓝色.
rgb(255,255, 255)或者#FFFFFF或者#FFF 表示纯白色.
rgb(0, 0,0)或者#000000 或者#000表示纯黑色.
当然,上述规则只是针对一般的程序而言是这么设定的.实际的显示器,可能有8bit色深或者
10bit色深等,实际情况会更加复杂.
获取计算机中 RGB 的小技巧。
在 QQ截图中,内置了一个获取颜色的RGB方式
QQ 截图的时候把鼠标光标放在想要获取的颜色上,即可看到 RGB