目录
(一)控件概述
1.1 关于控件体系的发展
(二)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
(三)小结
(一)控件概述
【解释说明】
- 像上述⽰例中的按钮、列表视图,、树形视图,、单⾏输⼊框、多⾏输⼊框、滚动条、下拉框等, 都可以称为 "控件".
🏕 综上, 学习Qt, 其中⼀个很重要的任务就是熟悉并掌握 Qt 内置的常⽤控件. 这些控件对于我们快速开发出符合需求的界⾯, 是⾄关重要的.
1.1 关于控件体系的发展
控件是 GUI 开发中的通⽤概念. 不仅仅局限在 Qt 中.
- 完全没有控件. 此时需要通过⼀些绘图 API ⼿动的绘制出按钮或者输⼊框等内容, 代码编写繁琐. 例如文曲星的 Lava 平台开发.
第⼆阶段:
- 只包含粗略的控件. 只是提供了按钮, 输⼊框, 单选框, 复选框等最常⽤的控件.
- 例如 html 的原⽣控件.
- 更完整的控件体系, 基本可以覆盖到 GUI 开发中的⼤部分场景.
- 例如早期的 MFC, VB, C++ Builder, Qt, Delphi, 后来的 Android SDK, Java FX, 前端的各种 UI 库等.
- 上图是前端中的Element-ui 中的控件概览, ⽆论是丰富程度还是颜值, 都⽐ Qt ⾃带的控件更胜⼀筹.
(二)QWidget 核心属性
在 Qt 中, 使用 QWidget 类表⽰ "控件". 像按钮, 视图, 输⼊框, 滚动条等具体的控件类, 都是继承⾃ QWidget.
【解释说明】
- 这些属性既可以通过 QtDesigner 会直接修改, 也可以通过代码的⽅式修改.
- 这些属性的具体含义, 在 Qt Assistant 中均有详细介绍.
- 在 Qt Assistant 中搜索 QWidget, 即可找到对应的⽂档说明. (或者在 Qt Creator 代码中, 选中QWidget, 按 F1 也可).
2.1 核心属性概览
下列表格列出了 QWidget 中的属性及其作用:
属性 | 作用 |
enabled | 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤. |
geometry | 位置和尺⼨. 包含 x, y, width, height 四个部分. 其中坐标是以⽗元素为参考进⾏设置的. |
windowTitle | 设置widget标题 |
windowIcon | 设置 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 |
accessibleDescripti on | 设置 widget 的详细描述. 作⽤同 accessibleName |
inputMethodHints | 针对输⼊框有效, ⽤来提⽰⽤⼾当前能输⼊的合法数据的格式. ⽐如只能输⼊数字, 只能输⼊⽇期等 |
2.2 enabled
API | 说明 |
isEnabled() | 获取到控件的可⽤状态. |
setEnabled | 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤. |
【解释说明】
- 所谓 "禁⽤" 指的是该控件不能接收任何⽤⼾的输⼊事件, 并且外观上往往是灰⾊的.
- 如果⼀个 widget 被禁⽤, 则该 widget 的⼦元素也被禁⽤.
代码示例: 使⽤代码创建⼀个禁⽤状态的按钮
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* btn = new QPushButton(this);btn->setText("这是个被禁⽤的按钮");btn->setEnabled(false);
}
运⾏程序, 可以看到按钮处于灰⾊状态, ⽆法被点击.
代码⽰例: 通过按钮2 切换按钮1 的禁⽤状态
1) 使⽤ Qt Designer 拖两个按钮到 Widget 中.
【解释说明】
两个按钮的 objectName 分别为 pushButton 和 pushButton_2;
QObject 的 objectName 属性介绍:
- QObject 是 QWidget 的⽗类. ⾥⾯最主要的属性就是 objectName
- 在⼀个 Qt 程序中, objectName 相当于对象的⾝份标识, 彼此之间不能重复
- 在使⽤ Qt Designer 时, 尤其是界⾯上存在多个 widget 的时候, 可以通过 objectName 获取到指定的 widget 对象
- Qt Designer ⽣成的 ui ⽂件, 本⾝是 xml 格式的. qmake 会把这个 xml ⽂件转换成 C++ 的 .h
- ⽂件(这个⽂件⽣成在 build ⽬录中), 构成⼀个 ui_widget 类
- 每个 widget 的 objectName 最终就会成为 ui_widget 类的属性名字
- 最终这个类的实例, 就是 Ui::Widget *ui , 因此就可以通过形如 ui->pushButton 或者 ui->pushButton_2 这样的代码获取到界⾯上的 widget 对象了.
class Ui_Widget
{
public:QPushButton *pushButton;QPushButton *pushButton_2;// ..................
}
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
- x 横坐标
- y 纵坐标
- width 宽度
- height ⾼度
- 但是实际开发中, 我们并不会直接使⽤这⼏个属性, ⽽是通过⼀系列封装的⽅法来获取/修改.
对于 Qt 的坐标系, 不要忘记是⼀个 "左⼿坐标系". 其中坐标系的原点是当前元素的⽗元素的左上⻆.
API | 说明 |
geometry() | 获取到控件的位置和尺⼨. 返回结果是⼀个 QRect, 包含了 x, y, width, height. 其中 x, y 是左上⻆的坐标. |
setGeometry(QRect) setGeometry(int x, int y, int width, int height) | 设置控件的位置和尺⼨. 可以直接设置⼀个 QRect, 也可以分四个属性单独设置. |
代码⽰例: 控制按钮的位置
1) 在界面中拖五个按钮.
2) 在 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());
}
2.4 windowTitle
API | 说明 |
windowTitle() | 获取到控件的窗⼝标题. |
setWindowTitle(const QString& title) | 设置控件的窗⼝标题. |
【注意】
- 上述设置操作针对不同的 widget 可能会有不同的⾏为.
- 如果是顶层 widget (独⽴窗⼝), 这个操作才会有效
- 如果是⼦ widget, 这个操作⽆任何效果
代码⽰例: 设置窗⼝标题
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 设置窗⼝标题this->setWindowTitle("这是标题");
}
2.5 windowIcon
API | 说明 |
windowIcon() | 获取到控件的窗⼝图标. 返回 QIcon 对象. |
setWindowIcon(const QIcon& icon ) | 设置控件的窗⼝图标. |
【注意】
- 同 windowTitle, 上述操作仅针对顶层 widget 有效.
代码⽰例: 设置窗⼝图标
2) 修改 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) 开头的路径.
- 相对路径: 以 . (表⽰当前路径) 或者 以 .. (表⽰当前路径上级路径) 开头的路径. 其中 . 经常也 会省略. 相对路径的前提是需要明确 "当前⼯作⽬录".
对于 Qt 程序来说, 当前⼯作⽬录可能是变化的. ⽐如通过 Qt Creator 运⾏的程序, 当前⼯作⽬录是项⽬的构建⽬录; 直接双击 exe 运⾏, ⼯作⽬录则是 exe 所在⽬录.
2.6 windowOpacity
API | 说明 |
windowOpacity() | 获取到控件的不透明数值. 返回 float, 取值为 0.0 -> 1.0 其中 0.0 表⽰全透明, 1.0 表⽰完全不透明. |
setWindowOpacity(flo at n) | 设置控件的不透明数值. |
代码⽰例: 调整窗⼝透明度
- objectName 分别为 pushButton_add 和 pushButton_sub
- 点击 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);
}
- 注意:C++ 中 float 类型遵守 IEEE 754 标准, 因此在进⾏运算的时候会有⼀定的精度误差. 因此 1 - 0.1 的数值并⾮是 0.9 .
2.7 cursor
API | 说明 |
cursor() | 获取到当前 widget 的 cursor 属性, 返回 QCursor 对象. 当⿏标悬停在该 widget 上时, 就会显⽰出对应的形状. |
setCursor(const QCursor& cursor) | 设置该 widget 光标的形状. 仅在⿏标停留在该 widget 上时⽣效. |
QGuiApplication::setOverrideCursor(co nst QCursor& cursor ) | 设置全局光标的形状. 对整个程序中的所有 widget 都会⽣效. 覆盖上⾯的 setCursor 设置的内容. |
代码⽰例: ⾃定义⿏标光标
2) 编写 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
API | 说明 |
font() | 获取当前 widget 的字体信息. 返回 QFont 对象. |
setFont(const QFont& font) | 设置当前 widget 的字体信息. |
属性 | 说明 |
family | 字体家族. ⽐如 "楷体", "宋体", "微软雅⿊" 等. |
pointSize | 字体大小 |
weight | 字体粗细. 以数值⽅式表⽰粗细程度取值范围为 [0, 99], 数值越⼤, 越粗. |
bold | 是否加粗. 设置为 true, 相当于 weight 为 75. 设置为 false 相当于weight 为 50. |
italic | 是否倾斜 |
underline | 是否带有下划线 |
strikeOut | 是否带有删除线 |
代码⽰例: 在 Qt Designer 中设置字体属性
- 在这⾥调整上述属性, 可以实时的看到⽂字的变化.
3) 执⾏程序, 观察效果
2.9 toolTip
API | 说明 |
setToolTip | 设置 toolTip. ⿏标悬停在该 widget 上时会有提⽰说明. |
setToolTipDuring | 设置 toolTip 提⽰的时间. 单位 ms. 时间到后 toolTip ⾃动消失. |
代码⽰例: 设置按钮的 toolTip
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
所谓 "焦点" , 指的就是能选中这个元素. 接下来的操作 (⽐如键盘操作), 就都是针对该焦点元素进⾏的了. 这个对于 输⼊框, 单选框, 复选框等控件⾮常有⽤的.这个事情就和 war3 或者 sc2 中, 先选中单位, 再下达命令是⼀样的
API | 说明 |
focusPolicy() | 获取该 widget 的 focusPolicy, 返回 Qt::FocusPolicy |
setFocusPolicy(Qt::FocusPolicy policy ) | 设置 widget 的 focusPolicy. |
- Qt::NoFocus :控件不会接收键盘焦点
- Qt::TabFocus :控件可以通过Tab键接收焦点
- Qt::ClickFocus :控件在⿏标点击时接收焦点
- Qt::StrongFocus :控件可以通过Tab键和⿏标点击接收焦点 (默认值)
- Qt::WheelFocus : 类似于 Qt::StrongFocus , 同时控件也通过⿏标滚轮获取到焦点 (新增
- 的选项, ⼀般很少使⽤).
代码⽰例: 理解不同的 focusPolicy
- 此时运⾏程序, 可以看到, 使⽤⿏标单击/tab, 就可以移动光标所在输⼊框. 从⽽接下来的输⼊就是针对这个获取焦点的输⼊框展开的了.
- 此时这个输⼊框也就⽆法输⼊内容了
2.11 styleSheet
通过 CSS 设置 widget 的样式.
CSS (Cascading Style Sheets 层叠样式表) 本⾝属于⽹⻚前端技术. 主要就是⽤来描述界⾯的样式.所谓 "样式", 包括不限于大小, 位置, 颜⾊, 间距, 字体, 背景, 边框等.我们平时看到的丰富多彩的⽹⻚, 就都会⽤到⼤量的 CSS.Qt 虽然是做 GUI 开发, 但实际上和 ⽹⻚前端 有很多异曲同⼯之处. 因此 Qt 也引⼊了对于 CSS的⽀持.
代码⽰例: 设置⽂本样式
1) 在界面上创建 label
- 此处的语法格式同 CSS, 使⽤键值对的⽅式设置样式. 其中键和值之间使⽤ : 分割. 键值对之间使⽤ ; 分割.
- 另外, Qt Designer 只能对样式的基本格式进⾏校验, 不能检测出哪些样式不被 Qt ⽀持. ⽐如 text-align: center 这样的⽂本居中操作, 就⽆法⽀持.
编辑完成样式之后, 可以看到在 Qt Designer 中能够实时预览出效果
3) 运⾏程序, 可以看到实际效果和预览效果基本⼀致. 、
(三)小结
QWidget 是 Qt 中最基本的用户界面类,它提供了一个抽象的概念,用于构建应用程序的窗口和用户界面。以下是 QWidget 的小结:
-
继承关系:QWidget 继承自 QObject 类,因此具有 QObject 的属性和方法。它还是许多其他用户界面部件的基类,如QPushButton、QLineEdit等。
-
窗口管理:QWidget 可以表示一个独立的窗口,也可以作为其他窗口部件的容器。它可以包含其他 QWidget 实例,形成层次结构。
-
事件处理:QWidget 可以响应用户输入和系统事件,如鼠标点击、键盘按键等。它提供了事件处理机制,可以重写事件处理函数来处理特定类型的事件。
-
样式和外观:QWidget 可以通过样式表来定制其外观和样式,包括背景颜色、字体、边框等。它还支持设置窗口图标、标题等属性。
总的来说,QWidget 提供了丰富的功能和灵活的扩展性,使得开发者可以方便地构建各种类型的用户界面应用程序。