控件和QWidget核心属性
目录
- 1. 控件概述
- 2. QWidget 核心属性
- 2.1 核心属性概览
- 2.2 enabled
- 2.3 geometry
- 2.4 windowTitle
- 2.5 windowIcon
- 2.6 windowOpacity
- 2.7 cursor
- 2.8 font
- 2.9 toolTip
- 2.10 focusPolicy
- 2.11 styleSheet
- 3. 核心属性总结
1. 控件概述
(1)Widget 是 Qt 中的核心概念。英文原义是 “小部件”,我们此处也把它翻译为 “控件”。控件是构成一个图形化界面的基本要素。
- 像上述示例中的按钮、列表视图、树形视图、单行输入框、多行输入框、滚动条、下拉框等,都可以称为 “控件”。
(2)Qt 作为⼀个成熟的 GUI 开发框架,内置了大量的常用控件。这⼀点在 Qt Designer 中就可以看到端倪。并且 Qt 也提供了 “自定义控件” 的能力,可以让程序猿在现有控件不能满足需求的时候,对现有控件做出扩展,或者手搓出新的控件。
- 综上,学习 Qt,其中⼀个很重要的任务就是熟悉并掌握 Qt 内置的常用控件。 这些控件对于我们快速开发出符合需求的界面是至关重要的。
(2)关于控件体系的发展控件是 GUI 开发中的通用概念。不仅仅局限在 Qt 中。
- 第一阶段:完全没有控件。此时需要通过⼀些绘图 API 手动的绘制出按钮或者输入框等内容,代码编写繁琐。例如文曲星的 Lava 平台开发。
- 第二阶段:只包含粗略的控件。只是提供了按钮、输入框、单选框、复选框等最常用的控件。 例如 html 的原生控件。
- 第三阶段:更完整的控件体系,基本可以覆盖到 GUI 开发中的大部分场景。 例如早期的 MFC、VB、C++ Builder、Qt、Delphi、后来的 Android SDK、Java FX、前端的各种 UI 库等。
- 上图是 前端中 的 Element-ui 中的控件概览,无论是丰富程度还是颜值,都比 Qt 自带的控件更胜一筹。
2. QWidget 核心属性
(1)在 Qt 中,使用 QWidget 类表示 “控件”。像按钮、视图、输入框、滚动条等具体的控件类都是继承自 QWidget。可以说QWidget 中就包含了 Qt 整个控件体系中通用的部分。
- 在 Qt Designer 中,随便拖一个控件过来,选中该控件,即可在右下方看到 QWidget 中的属性:
- 这些属性既可以通过 QtDesigner 会直接修改,也可以通过代码的方式修改。
- 这些属性的具体含义,在 Qt Assistant 中均有详细介绍。
- 在 Qt Assistant 中搜索 QWidget,即可找到对应的文档说明。(或者在 Qt Creator 代码中,选中 QWidget,按 F1 也可)。
2.1 核心属性概览
(1)下列表格列出了 QWidget 中的属性及其作用。
属性 | 作用 |
---|---|
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 中的样式。 Qt 中支持的样式非常丰富,对于前端开发人员上手是非常友好的。 |
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 | 指定窗口是否具有 “模态” 行为。 |
sizeIncrement | 拖动窗口大小时的增量单位。 |
baseSize | 窗口的基础大小,用来搭配 sizeIncrement 调整组件尺寸是计算组件应该调整到的合适的值。 |
palette | 调色板。可以设置 widget 的颜色风格。 |
mouseTracking | 是否要跟踪鼠标移动事件。 如果设为 true,表示需要跟踪,则鼠标划过的时候该 widget 就能持续收到鼠标移动事件。 如果设为 false,表示不需要跟踪,则鼠标划过的时候 widget 不会收到鼠标移动事件,只能收到鼠标按下或者释放的事件。 |
tabletTracking | 是否跟踪触摸屏的移动事件。 类似于 mouseTracking。Qt 5.9 中引入的新属性。 |
layoutDirection | 布局方向。Qt::LeftToRight:文本从左到右排列,也是默认值。 Qt::RightToLeft:文本从右到左排列。 Qt::GlobalAtomics:部件的布局方向由全局原子性决定(PS 这个翻译其实有点尴尬。其实就是根据应用程序中的其他 widget 布局方向确定的)。 |
autoFillBackground | 是否自动填充背景颜色。 |
windowFilePath | 能够把 widget 和⼀个本地文件路径关联起来。PS:其实作用不大。 |
accessibleName | 设置 widget 的可访问名称。这个名称可以被辅助技术 (像屏幕阅读器) 获取到。这个属性用于实现无障碍程序的场景中 (也就是给盲⼈写的程序)。PS:其实盲人也是可以使用电脑和手机的。甚至盲⼈还能成为程序猿。参见: https://www.bilibili.com/video/BV1954y1d7z9 |
accessibleDescription | 设置 widget 的详细描述。作用同 accessibleName |
inputMethodHints | 针对输⼊框有效,用来提示用户当前能输⼊的合法数据的格式。比如只能输入数字,只能输入日期等。 |
(2)接下来我们会介绍其中⼀些比较重要比较常用的属性,并附有代码示例。
- 注意:本章节的每个代码示例都是创建了单独的 Qt 项目。
2.2 enabled
(1)enabled 功能如下表格:
API | 说明 |
---|---|
isEnabled() | 获取到控件的可用状态. |
setEnabled | 设置控件是否可使用。true 表示可用,false 表示禁用。 |
- 所谓 “禁用” 指的是该控件不能接收任何用户的输⼊事件,并且外观上往往是灰色的。
- 如果⼀个 widget 被禁用,则该 widget 的子元素也被禁用。
(2)代码示例:使用代码创建⼀个禁用状态的按钮。
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* btn = new QPushButton(this);btn->setText("这是个被禁⽤的按钮");btn->setEnabled(false);
}
- 运行程序,可以看到按钮处于灰色状态,无法被点击。
(3)代码示例:通过按钮2 切换按钮1 的禁用状态。
- 使用 Qt Designer 拖两个按钮到 Widget 中:
- 两个按钮的 objectName 分别为 pushButton 和 pushButton_2。
- QObject 的 objectName 属性介绍:QObject 是 QWidget 的父类,其最重要的属性是 objectName。
- 唯一标识性:在一个 Qt 程序中,objectName 相当于对象的身份标识,彼此之间不可重复。
- Qt Designer 中的应用:当界面中存在多个 widget 时,可以通过 objectName 获取指定的 widget 对象。
- UI 文件的生成与转换:Qt Designer 生成的 .ui 文件本质是 XML 格式。qmake 会将此 XML 文件转换为 C++ 的 .h 文件(生成在 build 目录中),构成一个 ui_widget 类。
- objectName 的最终作用:每个 widget 的 objectName 会成为 ui_widget 类的属性名称。
- 最终通过类的实例 Ui::Widget *ui,即可通过类似 ui->pushButton 或 ui->pushButton_2 的代码访问界面上的 widget 对象。
class Ui_Widget
{
public:QPushButton *pushButton;QPushButton *pushButton_2;// ..................
}
- 生成两个按钮的 slot 函数:
- 使用 isEnabled 获取当前按钮的可用状态。
- 使用 setEnabled 修改按钮的可用状态。此处是直接针对原来的可用状态进行取反后设置。
void Widget::on_pushButton_clicked()
{qDebug() << "按下按钮";
}void Widget::on_pushButton_2_clicked()
{bool flag = this->ui->pushButton->isEnabled();this->ui->pushButton->setEnabled(!flag);
}
- 运行程序可以看到初始情况下上面的按钮是可用状态。点击下方按钮,即可使上方按钮被禁用;再次点击下方按钮,上方按钮就会解除禁用。(禁用状态的按钮为灰色,且不可点击)。
- 在 Qt Designer 中创建按钮的时候可以设置按钮的初始状态是 “可用” 还是 “禁用”。如果把 enabled 这一列的对钩去掉,则按钮的初始状态就是 “禁用” 状态。
2.3 geometry
(1)位置和尺寸。其实是四个属性的统称:
- x 横坐标 。
- y 纵坐标 。
- width 宽度 。
- height 高度。
- 但是实际开发中,我们并不会直接使用这几个属性,而是通过⼀系列封装的方法来获取/修改。
- 对于 Qt 的坐标系,不要忘记是⼀个 “左手坐标系”。其中坐标系的原点是当前元素的父元素的左上角。
(2)geometry 功能如下表格:
API | 说明 |
---|---|
geometry() | 获取到控件的位置和尺寸。返回结果是⼀个 QRect,包含了 x, y, width, height. 其中 x, y 是左上角的坐标。 |
setGeometry(QRect) | 设置控件的位置和尺寸, 直接设置⼀个 QRect。 |
setGeometry(int x, int y, int width, int height) | 设置控件的位置和尺寸,分四个属性单独设置。 |
(3)代码示例:控制按钮的位置。
- 在界面中拖五个按钮。 五个按钮的 objectName 分别为 pushButton_target , pushButton_up , pushButton_down , pushButton_left , pushButton_right 五个按钮的初始位置和大小都随意。
- 在 widget.cpp 中编写四个按钮的 slot 函数:
void Widget::on_pushButton_up_clicked()
{QRect rect = ui->pushButton_target->geometry();rect.setY(rect.y() - 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_down_clicked()
{QRect rect = ui->pushButton_target->geometry();rect.setY(rect.y() + 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_left_clicked()
{QRect rect = ui->pushButton_target->geometry();rect.setX(rect.x() - 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_right_clicked()
{QRect rect = ui->pushButton_target->geometry();rect.setX(rect.x() + 5);ui->pushButton_target->setGeometry(rect);
}
- 运行程序可以看到按下下方的四个按钮就会控制 target 的左上角的位置。对应的按钮整个尺寸也会发生改变。
- 上述代码中我们是直接设置的 QRect 中的 x, y。实际上 QRect 内部是存储了左上和右下两个点的坐标,再通过这两个点的坐标差值计算长宽。 单纯修改左上坐标就会引起整个矩形的长宽发生改变。
- 如果想让整个按钮都移动,可以改成下列代码:
void Widget::on_pushButton_up_clicked()
{QRect rect = ui->pushButton_target->geometry();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();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();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();ui->pushButton_target->setGeometry(rect.x() + 5, rect.y(), rect.width(), rect.height());
}
- 上述代码使用 move 方法也是可以的。
(4)代码示例:一个表白程序。
- 往界面上拖拽两个按钮和⼀个 Label。Label 的 objectName 为 pushButton_accept 和 pushButton_reject , label 的 objectName 为 label 。控件中文本如下图所示。
- 在 widget.cpp 中添加 slot 函数。
void Widget::on_pushButton_accept_clicked()
{ui->label->setText("⼥神快来嘴⼀个! mua~~");
}void Widget::on_pushButton_reject_pressed()
{// 获取窗⼝的宽度和⾼度int width = this->geometry().width();int height = this->geometry().height();// 重新⽣成按钮的位置.int x = rand() % width;int y = rand() % height;// 设置新的位置ui->pushButton_reject->move(x, y);
}
- 运行程序可以看到当点击 “残忍拒绝” 时按钮就跑了。
- 上述代码使用的是 pressed,鼠标按下事件。如果使用 mouseMoveEvent,会更狠⼀些,只要鼠标移动过来按钮就跑了。
- 对应的代码更麻烦⼀些 (需要自定义类继承自 QPushButton,重写mouseMoveEvent 方法)。
(5)window frame 的影响 :
- 如果 widget 作为⼀个窗口 (带有标题栏,最小化,最大化,关闭按钮),那么在计算尺寸和坐标的时候就有两种算法。包含 window frame 和 不包含 window frame。
- 其中 x()、y()、frameGeometry()、pos()、move() 都是按照包含 window frame 的方式来计算的。
- 其中 geometry()、width()、height()、rect()、size() 则是按照不包含 window frame 的方式来计算的。
- 当然,如果⼀个不是作为窗口的 widget,上述两类方式得到的结果是⼀致的。
(6)相关 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 对象 |
- 认真观察上面的表格可以看到,其实这里的 API 有 frameGeometry 和 geometry 两个就足够完成所有的需求了。
- 为什么要提供这么多功能重复的 API 呢?
- 这个就涉及到 Qt API 的设计理念了:尽量符合人的直觉。
(7)代码示例:感受 geometry 和 frameGeometry 的区别。
- 在界面上放置⼀个按钮。
- 在按钮的 slot 函数中编写代码:
void Widget::on_pushButton_clicked()
{QRect rect1 = this->geometry();QRect rect2 = this->frameGeometry();qDebug() << rect1;qDebug() << rect2;
}
- 在构造函数中也添加同样的代码:
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;
}
- 执行程序可以看到构造函数中打印出的 geometry 和 frameGeometry 是相同的。 但是在点击按钮时,打印的 geometry 和 frameGeometry 则存在差异:
(8)注意!!
- 在构造方法中Widget 刚刚创建出来,还没有加入到对象树中。此时也就不具备 Window frame。
- 在按钮的 slot 函数中,由于用户点击的时候,对象树已经构造好了,此时 Widget 已经具备了 Window frame,因此在位置和尺寸上均出现了差异。
- 如果把上述代码修改成打印 pushButton 的 geometry 和 frameGeometry,结果就是完全相同的。因为 pushButton 并非是⼀个窗口。
2.4 windowTitle
(1)windowTitle 功能如下表格:
API | 说明 |
---|---|
windowTitle() | 获取到控件的窗口标题。 |
setWindowTitle(const QString& title) | 设置控件的窗口标题。 |
- 注意! 上述设置操作针对不同的 widget 可能会有不同的行为。
- 如果是顶层 widget (独立窗口),这个操作才会有效。
- 如果是子 widget,这个操作无任何效果。
(2)代码示例:设置窗口标题。
- 修改 widget.cpp:
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 设置窗⼝标题this->setWindowTitle("这是标题");
}
- 执行效果:
2.5 windowIcon
(1)windowIcon 功能如下表格:
API | 说明 |
---|---|
windowIcon() | 获取到控件的窗口图标。返回 QIcon 对象。 |
setWindowIcon(const QIcon& icon) | 设置控件的窗口图标。 |
- 同 windowTitle,上述操作仅针对顶层 widget 有效。
(2)代码示例:设置窗口图标。
- 先在 D 盘中放⼀个图片,名字为 rose.jpg。
- 修改 widget.cpp:
#include <QIcon>
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 创建图标对象QIcon icon("d:/rose.jpg");// 设置图标this->setWindowIcon(icon);
}
- 注意:Windows 下路径的分隔符可以使用 / 也可以使用 \ 。但是如果在 字符串 中使用 \ 需要写作转义字符的形式 \ 。因此我们还是更推荐使用 / 。
- 运行程序可以看到窗口图标已经成为上述图片。
- 于此同时程序在任务栏中的图表也发生改变。
- 实际开发中我们⼀般不会在代码中通过绝对路径引入图片。因为我们无法保证程序发布后,用户的电脑上也有同样的路径。 如果用相对路径,则需要确保代码中的相对路径写法和图片实际所在的路径匹配 (比如代码中写作 “./image/rose.jpg”,就需要在当前工作目录中创建 image 目录,并把 rose.jpg 放进去)。
- 绝对路径:以盘符(windows)或者以 / (Linux) 开头的路径。
- 相对路径:以 . (表示当前路径) 或者 以 … (表示当前路径上级路径) 开头的路径。其中 . 经常也会省略。相对路径的前提是需要明确 “当前工作目录”。
(3)对于 Qt 程序来说当前工作目录可能是变化的。比如通过 Qt Creator 运行的程序,当前工作目录是项目的构建目录;直接双击 exe 运行,工作目录则是 exe 所在目录。
- 所谓构建目录是和 Qt 项目并列的,专门用来放生成的临时文件和最终 exe 的目录。
(4)代码示例:获取当前的工作目录。
- 在界面上创建⼀个比较大的 label,确保能把路径显示完整。objectName 使用默认的 label 即可。
- 修改 widget.cpp:使用 QDir::currentPath() 即可获取到当前工作目录。
#include <QDir>
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 获取到当前⼯作⽬录QString currentDir = QDir::currentPath();// 设置⼯作⽬录到 label 中.ui->label->setText(currentDir);
}
- 直接在 Qt Creator 中执行程序,可以看到当前工作目录是项目的构建目录。
- 进入上述构建目录,把里面的 exe 拷贝到其他目录中,比如 D: 中。再次执行程序,可以看到当前工作目录已经发生改变。
- 要想直接能双击 exe 运行需要先把 Qt 的路径添加到 path 环境变量中,否则会提示找不到动态库。这⼀点我们最开始搭建开发环境的时候已经操作过,此处不再赘述。
(5)注意上述构建目录, 是随时可删除的。比如点击菜单栏中的 “构建” -> “清理项目”,就会把这个目录中的内容清空掉。
- 因此如果我们把图片文件放到构建目录中,可能在不小心删除后就丢失了。我们还是希望能够把图片和源代码放到⼀起,并且使我们的程序无论拷贝到任何位置中都能正确使用图片。
(6)Qt 使用 qrc 机制帮我们自动完成了上述工作,更方便的来管理项目依赖的静态资源。
- qrc 文件是⼀种XML格式的资源配置文件,它用XML记录硬盘上的文件和对应的随意指定的资源名称。应用程序通过资源名称来访问这些资源。
- 在Qt开发中可以通过将资源文件添加到项目中来方便地访问和管理这些资源。这些资源文件可以位于qrc文件所在目录的同级或其子目录下。
- 在构建程序的过程中,Qt 会把资源文件的⼆进制数据转成 cpp 代码,编译到 exe 中。从而使依赖的资源变得 “路径无关”。
- 这种资源管理机制并非 Qt 独有,很多开发框架都有类似的机制。例如 Android 的 Resources 和 AssetManager 也是类似的效果。
(7)代码示例:通过 qrc 管理图片作为图标
- 右键项目创建⼀个 Qt Resource File (qrc 文件),文件名随意起(不要带中文), 此处叫做 resource.qrc。
- 在 qrc 编辑器中添加前缀。
- 此处我们前缀设置成 / 即可。所谓的前缀可以理解成 “目录”。这个前缀决定了后续我们如何在代码中访问资源。
- 在 资源编辑器 中点击 add Files 添加资源文件。此处我们需要添加的是rose.jpg。
- 注意:添加的文件必须是在 qrc 文件的同级目录或者同级目录的子目录中。因此我们需要把之前 D 盘中的 rose.jpg 复制到上述目录中。
- 在代码中使用 rose.jpg。编辑 widget.cpp:
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 访问到 rose.jpg 资源QIcon icon(":/rose.jpg");// 设置图标this->setWindowIcon(icon);
}
- 注意上述路径的访问规则:
- 使用:作为开头,表示从 qrc 中读取资源。
- / 是上面配置的前缀。
- rose.jpg 是资源的名称。
- 需要确保代码中编写的路径和添加到 qrc 中资源的路径匹配。否则资源无法被访问 (同时也不会有报错提示)。
- 运行程序,可以看到图标已经能正确设置。
(8)接下来我们可以进入到项目的构建目录,可以看到目录中多了一个 qrc_resource.cpp 文件。直接打开这个文件可以看到类似如下代码:
static const unsigned char qt_resource_data[] = {// D:/project/ke/qt/DemoCode/DemoWindowIconQrc/rose.jpg0x0,0x0,0x33,0x2,0xff,0xd8,0xff,0xe0,0x0,0x10,0x4a,0x46,0x49,0x46,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0xff,0xfe,0x0,0x3b,0x43,0x52,0x45,0x41,0x54,0x4f,0x52,0x3a,0x20,0x67,0x64,0x2d,0x6a,0x70,0x65,0x67,0x20,0x76,0x31,0x2e,0x30,0x20,0x28,0x75,0x73,0x69,0x6e,0x67,0x20,0x49,0x4a,0x47,0x20,0x4a,0x50,0x45,0x47,0x20,0x76,0x36,0x32,0x29,0x2c,0x20,0x71,0x75,0x61,0x6c,0x69,0x74,0x79,0x20,0x3d,0x20,0x39,0x35,0xa,0xff,0xdb,0x0,0x43,0x0,0x2,0x1,0x1,0x1,0x1,0x1,0x2,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x4,0x3,0x2,0x2,0x2,0x2,0x5,0x4,0x4,0x3,0x4,0x6,0x5,0x6,0x6,0x6,0x5,0x6,0x6,0x6,0x7,0x9,0x8,0x6,0x7,0x9,0x7,0x6,0x6,0x8,0xb,0x8,0x9,0xa,0xa,0xa,0xa,0xa,0x6,0x8,0xb,0xc,0xb,0xa,0xc,0x9,0xa,0xa,0xa,0xff,0xdb,0x0,0x43,0x1,0x2,0x2,0x2,0x2,0x2,0x2,// .............
};
- 上述代码其实就是通过 unsigned char 数组,把 rose.jpg 中的每个字节都记录下来。这些代码会被编译到 exe 中。后续无论 exe 被复制到哪个目录下,都确保能够访问到该图片资源。
(9)上述 qrc 这一套资源管理方案优点和缺点都很明显:
- 优点:确保了图片、字体、声音等资源能够真正做到 “目录无关”,无论如何都不会出现资源丢失的情况。
- 缺点:不适合管理体积大的资源。如果资源比较大 (比如是几个 MB 的文件),或者资源特别多,生成的最终的 exe 体积就会比较大,程序运行消耗的内存也会增大,程序编译的时间也会显著增加。
2.6 windowOpacity
(1)windowOpacity 功能如下表格:
API | 说明 |
---|---|
windowOpacity() | 获取到控件的不透明数值。返回 float,取值为 0.0 -> 1.0 其中 0.0 表示全透明,1.0 表示完全不透明。 |
setWindowOpacity(float n) | 设置控件的不透明数值。 |
(2)代码示例:调整窗口透明度。
- 在界面上拖放两个按钮,分别用来增加不透明度和减少不透明度。
- 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);
}
- 执行程序可以看到点击了几下 - 之后就可以透过窗口看到后面的猫猫头了。点击 + 又会逐渐恢复。
- 同时控制台中也可以看到 opacity 数值的变化。
- 注意:C++ 中 float 类型遵守 IEEE 754 标准,因此在进行运算的时候会有⼀定的精度误差。因此 1 - 0.1 的数值并非是 0.9。
2.7 cursor
(1)cursor 功能如下表格:
API | 说明 |
---|---|
cursor() | 获取到当前 widget 的 cursor 属性,返回 QCursor 对象。当鼠标悬停在该 widget 上时,就会显示出对应的形状。 |
setCursor(const QCursor& cursor) | 设置该 widget 光标的形状。仅在鼠标停留在该 widget 上时生效。 |
QGuiApplication::setOverrideCursor(const QCursor& cursor) | 设置全局光标的形状。对整个程序中的所有 widget 都会生效。覆盖上面的 setCursor 设置的内容。 |
(2)代码示例:在 Qt Designer 中设置按钮的光标。
- 在界面中创建⼀个按钮。
- 直接在右侧属性编辑区修改 cursor 属性为 “等待”。
- 运行程序,鼠标悬停到按钮上即可看到光标的变化。
(3)代码示例:通过代码设置按钮的光标。
- 编写 widget.cpp。
- 其中 Qt::WaitCursor 就是自带的沙漏形状的光标。
#include <QPushButton>
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 创建按钮QPushButton* button = new QPushButton(this);button->resize(100, 50);button->move(100, 100);button->setText("这是⼀个按钮");// 设置按钮的 cursorbutton->setCursor(QCursor(Qt::WaitCursor));
}
- 系统内置的光标形状如下:
- Ctrl + 左键 点击 Qt::WaitCursor 跳转到源码即可看到。
enum CursorShape {ArrowCursor,UpArrowCursor,CrossCursor,WaitCursor,IBeamCursor,SizeVerCursor,SizeHorCursor,SizeBDiagCursor,SizeFDiagCursor,SizeAllCursor,BlankCursor,SplitVCursor,SplitHCursor,PointingHandCursor,ForbiddenCursor,WhatsThisCursor,BusyCursor,OpenHandCursor,ClosedHandCursor,DragCopyCursor,DragMoveCursor,DragLinkCursor,LastCursor = DragLinkCursor,BitmapCursor = 24,CustomCursor = 25
}
- 运行程序观察效果。
(4)代码示例:自定义鼠标光标。
- Qt 自带的光标形状有限。我们也可以自己找个图片做成鼠标的光标。比如我们有请滑稽老铁。
- 创建 qrc 资源文件,添加前缀 / ,并加入 huaji.png。
- 编写 widget.cpp:
#include <QPixmap>
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 创建⼀个位图对象, 加载⾃定义光标图⽚QPixmap pixmap(":/huaji.png");// 缩放图⽚为 64 * 64 的尺⼨.pixmap = pixmap.scaled(64, 64);// 创建 QCursor 对象, 并指定 "热点" 为 (2, 2) 坐标位置.// 所谓 "热点" 就是⿏标点击时⽣效的位置.QCursor cursor(pixmap, 2, 2);// 设置光标this->setCursor(cursor);
}
- 运行程序观察效果。
2.8 font
(1)font 功能如下表格:
API | 说明 |
---|---|
font() | 获取当前 widget 的字体信息。返回 QFont 对象。 |
setFont(const QFont& font) | 设置当前 widget 的字体信息 |
(2)关于 QFont:
属性 | 说明 |
---|---|
family | 字体家族。比如 “楷体”,“宋体”,“微软雅⿊” 等。 |
pointSize | 字体大小 |
weight | 字体粗细。以数值方式表示粗细程度取值范围为 [0, 99],数值越大,越粗。 |
bold | 是否加粗。设置为 true,相当于 weight 为 75。设置为 false 相当于 weight 为 50。 |
italic | 是否倾斜 |
underline | 是否带有下划线 |
strikeOut | 是否带有删除线 |
(3)代码示例:在 Qt Designer 中设置字体属性。
- 在界面上创建⼀个 label。
- 在右侧的属性编辑区,设置该 label 的 font 相关属性。在这里调整上述属性,可以实时的看到文字的变化。
- 执行程序观察效果。
(4)代码示例:在代码中设置字体属性。
- 在界面中创建 label、objectName 使用默认的 label 即可。
- 修改 widget.cpp:
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 设置 label 的⽂本内容ui->label->setText("这是⼀段⽂本");// 创建字体对象QFont font;// 设置字体家族font.setFamily("仿宋");// 设置字体⼤⼩font.setPointSize(20);// 设置字体加粗font.setBold(true);// 设置字体倾斜font.setItalic(true);// 设置字体下划线font.setUnderline(true);// 设置字体删除线font.setStrikeOut(true);// 设置字体对象到 label 上ui->label->setFont(font);
}
- 运行程序观察效果。
- 实际开发中字体属性如何选择是⼀个 “审美问题”,而不是 “技术问题”。往往需要有⼀定的艺术细菌。
- 幸运的是公司中往往有专业的 “美工” / “设计” 这样的岗位去做这方面的工作。 咱们程序员只要按照人家给的设计稿,把代码写出来即可。不必过多考虑怎样搭配才好看的问题。
2.9 toolTip
(1)toolTip 功能如下表格:
API | 说明 |
---|---|
setToolTip | 设置 toolTip。鼠标悬停在该 widget 上时会有提示说明。 |
setToolTipDuring | 设置 toolTip 提示的时间。单位 ms。时间到后 toolTip 自动消失。 |
- toolTip 只是给用户看的。在代码中⼀般不需要获取到 toolTip。
(2)代码示例:设置按钮的 toolTip。
- 在界面上拖放两个按钮。objectName 设置为 pushButton_yes 和 pushButton_no。
- 编写 widget.cpp:
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);ui->pushButton_yes->setToolTip("这个是 yes 按钮");ui->pushButton_yes->setToolTipDuration(3000);ui->pushButton_no->setToolTip("这个是 no 按钮");ui->pushButton_no->setToolTipDuration(10000);
}
- 运行程序观察效果。可以看到鼠标停到按钮上之后就能弹出提示。时间到后自己消失。
2.10 focusPolicy
(1)设置控件获取到焦点的策略。比如某个控件能否用鼠标选中或者能否通过 tab 键选中。所谓 “焦点” 指的就是能选中这个元素。接下来的操作 (比如键盘操作),就都是针对该焦点元素进行的了。这个对于 输⼊框,单选框,复选框等控件非常有用的。
- 这个事情就和 war3 或者 sc2 中,先选中单位,再下达命令是⼀样的:
(2)focusPolicy 功能如下表格:
API | 说明 |
---|---|
focusPolicy() | 获取该 widget 的 focusPolicy,返回 Qt::FocusPolicy。 |
setFocusPolicy(Qt::FocusPolicy policy) | 设置 widget 的 focusPolicy。 |
(3)Qt::FocusPolicy 是⼀个枚举类型。取值如下:
- Qt::NoFocus:控件不会接收键盘焦点。
- Qt::TabFocus:控件可以通过Tab键接收焦点 。
- Qt::ClickFocus:控件在鼠标点击时接收焦点。
- Qt::StrongFocus:控件可以通过Tab键和鼠标点击接收焦点 (默认值) 。
- Qt::WheelFocus:类似于 Qt::StrongFocus,同时控件也通过鼠标滚轮获取到焦点 (新增的选项,⼀般很少使用)。
(4)代码示例:理解不同的 focusPolicy。
- 在界面上创建四个单行输入框 (Line Edit) 。
- 修改四个输入框的 focusPolicy 属性为 Qt::StrongFocus (默认取值,⼀般不用额外修改) 。
此时运行程序可以看到使用鼠标单击/tab,就可以移动光标所在输入框。从而接下来的输入就是针对这个获取焦点的输入框展开的了。
- 修改第二个输入框的 focusPolicy 为 Qt::NoFocus , 则第二个输入框不会被 tab / 鼠标左键选中。
此时这个输入框也就无法输入内容了。
- 修改第二个输入框 focusPolicy 为 Qt::TabFocus,则只能通过 tab 选中,无法通过鼠标选中。
- 修改第⼆个输入框 focusPolicy 为 Qt::ClickFocus,则只能通过 tab 选中,无法通过鼠标选中。
2.11 styleSheet
(1)通过 CSS 设置 widget 的样式:
- CSS (Cascading Style Sheets 层叠样式表) 本身属于网页前端技术。主要就是用来描述界面的样式。
- 所谓 "样式"包括不限于大小,位置,颜色,间距,字体,背景,边框等。
- 我们平时看到的丰富多彩的网页,就都会用到大量的 CSS。 Qt 虽然是做 GUI 开发,但实际上和 网页前端 有很多异曲同工之处。因此 Qt 也引入了对于 CSS的支持。
- CSS 中可以设置的样式属性非常多。基于这些属性 Qt 只能支持其中⼀部分,称为 QSS (Qt Style Sheet) 。具体的支持情况可以参考 Qt 文档中 “Qt Style Sheets Reference” 章节。此处只是进行一个简单的演示。
(2)代码示例:设置文本样式
- 在界面上创建 label:
- 编辑右侧的 styleSheet 属性设置样式:
此处的语法格式同 CSS,使用键值对的方式设置样式。其中键和值之间使用 : 分割。键值对之间使用 ; 分割。另外,Qt Designer 只能对样式的基本格式进行校验,不能检测出哪些样式不被 Qt 支持。比如 textalign: center 这样的文本居中操作就无法支持。
- 编辑完成样式之后,可以看到在 Qt Designer 中能够实时预览出效果。
(3)代码示例:实现切换夜间模式。
- 在界面上创建⼀个多行输入框 (Text Edit) 和两个按钮。
- objectName 分别为 pushButton_light 和 pushButton_dark。
- 编写按钮的 slot 函数:
- #333 是深色,但是没那么黑。
- #fff 是纯白色。
- #000 是纯黑色。
- 使用在线调色板或者画图板都可以看到数字对应的颜色。参考:
https://www.sojson.com/web/online.html
void Widget::on_pushButton_dark_clicked()
{this->setStyleSheet("background-color: #333");ui->textEdit->setStyleSheet("background-color: #333; color: #fff;");ui->pushButton_light->setStyleSheet("color: #fff");ui->pushButton_dark->setStyleSheet("color: #fff");
}void Widget::on_pushButton_light_clicked()
{this->setStyleSheet("background-color: #f3f3f3");ui->textEdit->setStyleSheet("background-color: #fff; color: #000;");ui->pushButton_light->setStyleSheet("color: #000");ui->pushButton_dark->setStyleSheet("color: #000");
}
-
关于计算机中的颜色表示:
- 计算机中使用 “像素” 表示屏幕上的⼀个基本单位(也就是⼀个发亮的光点)。 每个光点都使用三个字节表示色,分别是 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 色深等,实际情况会更加复杂。
- 计算机中使用 “像素” 表示屏幕上的⼀个基本单位(也就是⼀个发亮的光点)。 每个光点都使用三个字节表示色,分别是 R (red),G (green),B (blue) ⼀个字节表示 (取值范围是 0-255,或者 0x00-0xFF)。混合三种不同颜色的数值比例,就能搭配出千千万万的颜色出来。
-
运行程序,点击 “日间模式”,就是浅色背景,深色文字;点击 “夜间模式”,就是深色背景,浅色文字。
3. 核心属性总结
(1)基本属性:
- enabled:
- 作用:控件是否可用(true 为启用,false 为禁用,禁用后无法响应用户操作)。
- 示例:setEnabled(false) 禁用按钮。
- geometry:
- 作用:控件的几何位置和大小(包含窗口边框),格式为 QRect(x, y, width, height)。
- 示例:setGeometry(100, 100, 200, 50) 设置控件位置及尺寸。
- windowTitle:
- 作用:窗口标题(仅对顶级窗口有效)。
- 示例:setWindowTitle(“主窗口”)。
- windowOpacity:
- 作用:窗口透明度(0.0 完全透明,1.0 不透明)。
- 示例:setWindowOpacity(0.8)。
- windowIcon:
- 作用:窗口图标(仅对顶级窗口有效)。
- 示例:setWindowIcon(QIcon(“:/icon.png”))。
(2)位置与尺寸:
- pos() / move(x, y)
- 作用:控件的位置(相对于父容器的左上角坐标)。
- 示例:move(50, 50)。
- size() / resize(width, height)
- 作用:控件的尺寸(不包含窗口边框)。
- 示例:resize(300, 200)。
- frameGeometry()
- 作用:控件实际占用的几何区域(包含窗口边框)。
- minimumSize / maximumSize
- 作用:控件的最小和最大允许尺寸。
- 示例:setMinimumSize(100, 50)。
(3)外观与样式:
- styleSheet
- 作用:通过 CSS 样式表自定义控件外观。
- 示例:setStyleSheet(“QPushButton { background-color: red; }”);
- palette
- 作用:控件的调色板(颜色方案),用于统一界面风格。
- 示例:设置背景色、文本颜色等。
- font
- 作用:控件的字体属性(字体类型、大小、粗细等)。
- 示例:setFont(QFont(“Arial”, 12))。
(4)焦点与交互:
- focusPolicy
- 作用:控件的焦点获取策略(如 Qt::TabFocus 支持 Tab 键切换焦点)。
- 选项:NoFocus, TabFocus, ClickFocus, StrongFocus 等。
- hasFocus()
- 作用:判断控件是否当前拥有键盘焦点。
- toolTip
- 作用:鼠标悬停时显示的提示文本。
- 示例:setToolTip(“点击保存文件”)。
(5)可见性与状态:
- visible
- 作用:控件是否可见(true 可见,false 隐藏)。
- 示例:hide() 或 show()。
- cursor
- 作用:鼠标悬停在控件上时的光标形状。
- 示例:setCursor(Qt::WaitCursor) 设置等待光标。
- mouseTracking
- 作用:是否启用鼠标移动跟踪(默认 false,仅在有鼠标按下时触发事件)。
- 示例:实时跟踪鼠标位置需设为 true。
(6)布局与父子关系:
- parent
- 作用:控件的父对象(用于对象树管理,父控件销毁时子控件自动销毁)。
- children()
- 作用:获取控件的所有子对象列表。
- layout()
- 作用:控件的布局管理器(如 QHBoxLayout, QVBoxLayout)。
(7)其他关键属性:
- objectName
- 作用:控件的唯一标识符(用于通过 findChild 查找对象)。
- windowFlags
- 作用:窗口的标志(如无边框窗口 Qt::FramelessWindowHint)。
- sizePolicy
- 作用:控件在布局中的尺寸调整策略(如 QSizePolicy::Expanding)。
(8)整体总结:
- QWidget 的属性覆盖了控件的位置、外观、交互、状态管理等核心功能。开发者可通过这些属性灵活定制界面行为,结合信号与槽机制,实现复杂的用户交互逻辑。