5.常用控件-QWidget|enabled|geometry|window frame(C++)
控件概述
实现图形化界面的程序.
 Qt中已经给我们提供了很多的“控件"
 ![![[Pasted image 20250418161607.png]]](https://i-blog.csdnimg.cn/direct/82648d2abf8345569ffa9e99e50752ca.png)
就需要学习和了解这些控件,学会如何使用这些控件
 编程讲究的是“站在巨人的肩膀上”,而不是“从头发明轮子"
 一个图形化界面上的内容,不需要咱们全都从零去实现.Qt中已经提供了很多内置的控件了(按钮,文本框,单选按钮,复选按钮,下拉框.) 咱们拿过来就能直接使用.
 ![![[Pasted image 20250418160915.png]]](https://i-blog.csdnimg.cn/direct/9a3fc5fe6ff34e93b5be763c7de2a647.png)
QWidget核⼼属性
在Qt中,使⽤QWidget类表⽰"控件"。像按钮,视图,输⼊框,滚动条等具体的控件类,都是继承⾃QWidget.
 可以说,QWidget中就包含了Qt整个控件体系中,通⽤的部分.
 在QtDesigner中,随便拖⼀个控件过来,选中该控件,即可在右下⽅看到QWidget中的属性
 ![![[Pasted image 20250418161043.png]]](https://i-blog.csdnimg.cn/direct/bd07629c14bc40268edf40cb9553b50e.png)
这些属性既可以通过QtDesigner会直接修改,也可以通过代码的⽅式修改.
 这些属性的具体含义,在Qt Assistant中均有详细介绍.
 在Qt Assistant中搜索QWidget,即可找到对应的⽂档说明。(或者在Qt Creator代码中,选中QWidget,按F1也可).
核⼼属性概览
| 属性 | 作⽤ | 
|---|---|
| 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.Qt5.9中引⼊的新属性.  | 
| layoutDirection | 布局⽅向. • Qt::LeftToRight:⽂本从左到右排列,也是默认值。 • Qt::RightToLeft:⽂本从右到左排列。 • Qt::GlobalAtomics:部件的布局⽅向由全局原⼦性决定(这个翻译其实有点尴尬.其实就是根据应⽤程序中的其他widget布局⽅向确的).  | 
| autoFillBackground | 是否⾃动填充背景颜⾊. | 
| windowFilePath | 能够把widget和⼀个本地⽂件路径关联起来. | 
| accessibleName | 设置widget的可访问名称.这个名称可以被辅助技术(像屏幕阅读器)获取到.这个属性⽤于实现⽆障碍程序的场景中(也就是给盲⼈写的程序). | 
| accessibleDescription | 设置widget的详细描述.作⽤同accessibleName | 
| inputMethodHints | 针对输⼊框有效,⽤来提⽰⽤⼾当前能输⼊的合法数据的格式.⽐如只能输⼊数字,只能输⼊⽇期等. | 
enabled
| API | 说明 | 
|---|---|
| isEnabled() | 获取到控件的可⽤状态. | 
| setEnabled | 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤. | 
- 所谓"禁⽤"指的是该控件不能接收任何⽤⼾的输⼊事件,并且外观上往往是灰⾊的.
 - 如果⼀个widget被禁⽤,则该widget的⼦元素也被禁⽤
 
代码⽰例:使⽤代码创建⼀个禁⽤状态的按钮
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("按钮");//按钮处于禁用状态button->setEnabled(false);
}Widget::~Widget()
{delete ui;
}
 
![![[Pasted image 20250418165521.png]]](https://i-blog.csdnimg.cn/direct/0b98b54a40af43c3bcbc2a8ebd31f5d0.png)
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("按钮");//按钮处于禁用状态button->setEnabled(false);connect(button, &QPushButton::clicked, this, &Widget::handle);
}Widget::~Widget()
{delete ui;
}void Widget::handle()
{qDebug() << "handle";
}
 
加上槽函数,同样用不了
切换禁用状态
 创建两个按钮
 ![![[Pasted image 20250418170818.png]]](https://i-blog.csdnimg.cn/direct/43c556fb834c4abab91d3616d9730471.png)
转到槽,分别给两个按钮插入clicked()
#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() << "执行了槽函数";
}void Widget::on_pushButton_2_clicked()
{// 切换第一个按钮的禁用状态// 1.先获取到第一个按钮当前的状态bool enable = ui->pushButton->isEnabled();if (enable) {ui->pushButton->setEnabled(false);}else {ui->pushButton->setEnabled(true);}
}
 
运⾏程序,可以看到,初始情况下,上⾯的按钮是可⽤状态.
 点击下⽅按钮,即可使上⽅按钮被禁⽤;再次点击下⽅按钮,上⽅按钮就会解除禁⽤.(禁⽤状态的按钮为灰⾊,且不可点击).
 ![![[Pasted image 20250418172012.png]]](https://i-blog.csdnimg.cn/direct/db315656857f412a9b0de3abbdc52269.png)
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对象了.
在Qt Designer中创建按钮的时候,可以设置按钮的初始状态是"可⽤"还是"禁⽤".
 如果把enabled这⼀列的对钩去掉,则按钮的初始状态就是"禁⽤"状态.
 ![![[Pasted image 20250418181800.png]]](https://i-blog.csdnimg.cn/direct/62de7751fc214f80ae2dc6e78dd8d9d0.png)
geometry
位置和尺⼨.其实是四个属性的统称:
- x 横坐标
 - y 纵坐标
 - width 宽度
 - height ⾼度
![![[Pasted image 20250418183835.png]]](https://i-blog.csdnimg.cn/direct/8bc11e6ea14e455cb835adb03f95547f.png)
 
但是实际开发中,我们并不会直接使⽤这⼏个属性,⽽是通过⼀系列封装的⽅法来获取/修改.
 对于Qt的坐标系,不要忘记是⼀个"左⼿坐标系".其中坐标系的原点是当前元素的⽗元素的左上⻆
 ![![[Pasted image 20250418183901.png]]](https://i-blog.csdnimg.cn/direct/92729e2a3700431c88c891f665c8e6d6.png)
| API | 说明 | 
|---|---|
| geometry() | 获取到控件的位置和尺⼨.返回结果是⼀个QRect,包含了x,y,width,height.其中x,y是左上⻆的坐标. | 
| setGeometry(QRect) setGeometry(int x,int y,int width,int height)  | 设置控件的位置和尺⼨.可以直接设置⼀个QRect,也可以分四个属性单独设置 | 
Rect就是矩形
 Qt中针对一些几何上的概念也进行了封装
 QPoint表示一个点 QRect表示一个矩形
 属于是小对象,里面的属性非常少,占用空间也小.
 C++中使用上述对象,通常就会按照值的方式来传递参数了
 move只是修改位置
 setGeometry既可以修改位置,又可以修改尺寸~
代码⽰例:控制按钮的位置
![![[Pasted image 20250418185512.png]]](https://i-blog.csdnimg.cn/direct/f502e84179484872b1d0819d73bdff12.png)
创建一个按钮target
 ![![[Pasted image 20250418185521.png]]](https://i-blog.csdnimg.cn/direct/4a8e3a851dbf4aceb2ba321f2b4e2b99.png)
修改objectName为pushButton_target
 修改这些属性的时候,一定要先确认好你当前选中的是哪个控件
![![[Pasted image 20250418185722.png]]](https://i-blog.csdnimg.cn/direct/1e5effc58df047aaa92e80cfa852a091.png)
1)在界⾯中拖五个按钮.
 五个按钮的objectName分别为 pushButton_target , pushButton_up ,pushButton_down , pushButton_left , pushButton_right
 五个按钮的初始位置和⼤⼩都随意
 期望通过点击这几个按钮,就能够修改target按钮的geometry
#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本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;
}
 
![![[Pasted image 20250418190311.png]]](https://i-blog.csdnimg.cn/direct/ad23295d1df84802ae346bda003ede27.png)
单位都是像素
void Widget::on_pushButton_up_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setY(rect.y() - 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_down_clicked()
{QRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setY(rect.y() + 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_left_clicked()
{QRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setX(rect.x() - 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_right_clicked()
{QRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setX(rect.x() + 5);ui->pushButton_target->setGeometry(rect);
}
 
![![[Pasted image 20250418191804.png]]](https://i-blog.csdnimg.cn/direct/b6a842ee80154bb29f46e3485068d6ec.png)
![![[Pasted image 20250418191811.png]]](https://i-blog.csdnimg.cn/direct/8a2d98817d704e0faccfdf89232dd42d.png)
当前代码实际执行的效果,是在调整左上角位置.左上角位置改变的同时,高度和宽度也同时发生了改变
 如果想要让这个按钮能够平移.(宽度高度不变,整个按钮的位置都发生改变)
 刚才的代码,修改的是QRect对象的×和y.这样的修改就会使QRect宽度高度发生改变
 如何才能实现“平移”的效果,保持尺寸不变,整个按钮位置变化?
 不再修改QRect,而是通过QRect基于setGeometry第二个版本的函数重新设置位置即可.
void Widget::on_pushButton_up_clicked()
{// 获取到target本身的geometryQRect 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());
}
 
![![[Pasted image 20250418193200.png]]](https://i-blog.csdnimg.cn/direct/4ffa787628e6427c973ff22902c6a12b.png)
代码⽰例:⼀个表⽩程序
1)往界⾯上拖拽两个按钮和⼀个Label.
 PushButton的objectName为 pushButton_accept 和 pushButton_reject ,label的objectName为 label
 控件中⽂本如下图所⽰
 ![![[Pasted image 20250418193844.png]]](https://i-blog.csdnimg.cn/direct/70f7d697695748bb91b5553dd63f932b.png)
void Widget::on_pushButton_accept_clicked()
{ui->label->setText("女神,嘴一个");
}
 
![![[Pasted image 20250418194242.png]]](https://i-blog.csdnimg.cn/direct/d622af9e2695423e8cbbbb94e7f5ec1b.png)
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 设置随机种子,使用时间戳作为随机种子srand(time(0));
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_accept_clicked()
{ui->label->setText("女神,嘴一个");
}void Widget::on_pushButton_reject_clicked()
{// 如果点击了这个按钮,就把这个按钮挪走// 通过生成随机数的方式来确定按钮新的位置// 获取到当前程序窗口的尺寸int width = this->geometry().width();int height = this->geometry().height();// 重新生成按钮的位置int x = rand() % width;int y = rand() % height;// 移动按钮的位置ui->pushButton_reject->move(x, y);
}
 
rand(是c标准库中的函数
 能够生成一个随机的整数.这个数字范围很大~~
 上述代码就类似于之前写猜数字,要生成一个1-100之间的整数
rand0 % 100 + 1
[0, 99] + 1 => [1, 100]
 
rand函数使用之前要设置随机种子~^
 C语言中通过time可以获取到秒级时间戳~~
 ![![[Pasted image 20250418195718.png]]](https://i-blog.csdnimg.cn/direct/945668462acb4438ab40d233e400480f.png)
按钮提供的信号不止有点击
 一下一上是点击,
 不再使用clicked信号,换成pressed.鼠标按下的时候触发
 ![![[Pasted image 20250418200054.png]]](https://i-blog.csdnimg.cn/direct/f2d3dac7171a4875b625346ab9647757.png)
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);
}
 
也可以做到,鼠标不点击,只要挪到按钮上,就会让按钮移动~~(需要使用到Qt中的事件机制)
window frame
如果widget作为⼀个窗⼝(带有标题栏,最⼩化,最⼤化,关闭按钮),那么在计算尺⼨和坐标的时候就有两种算法.包含window frame和不包含window frame.
 其中x(),y(),frameGeometry(),pos(),move()都是按照包含window frame的⽅式来计算的.
 其中geometry(),width(),height(),rect(),size()则是按照不包含window frame的⽅式来计算的.
 当然,如果⼀个不是作为窗⼝的widget,上述两类⽅式得到的结果是⼀致的
 ![![[Pasted image 20250418201635.png]]](https://i-blog.csdnimg.cn/direct/ee6b725456184705bad0939dd3ce07da.png)
| 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对象.  | 
| 在Qt中,关于位置尺寸,提供了很多的API. | |
| 有的API的位置信息是以Widget本体左上角为原点的(不考虑Windowframe) 有的API的位置信息是以windowframe左上角为原点的. | |
| geometry() | |
| setGeometry()都是不考虑windowframe | |
| frameGeometry() | |
| setFrameGeometry()考虑windowframe | |
| 其实这⾥的API有frameGeometry和geometry两个就⾜够完成所有的需求了. | 
代码⽰例:感受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对象来使用geometry和frameGeometry。观察区别QRect rect1 = this->geometry();QRect rect2 = this->frameGeometry();qDebug() << rect1;qDebug() << rect2;
}Widget::~Widget()
{delete ui;
}
 
![![[Pasted image 20250418205623.png]]](https://i-blog.csdnimg.cn/direct/eed8fe550d24477097e193565f362692.png)
当前代码是放到了构造函数中. 此时这个Widget对象正在构造还没有被加入到windowframe中
 因此,此时还看不到windowframe的影响,
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 直接针对Widget对象来使用geometry和frameGeometry。观察区别
//    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;
}
 
![![[Pasted image 20250418210248.png]]](https://i-blog.csdnimg.cn/direct/848b58b2802247d8be613c2ae79d5f3c.png)
