文章目录
- 信号与槽
- 常用控件
-
- QWidget
-
- enabled
- geometry
- [window frame的影响](#window frame的影响)
- windowTitle
- windowIcon
- windowOpacity
- cursor
- font
- toolTip
- focusPolicy
- styleSheet
- 什么时候用ui->,什么时候用this->
信号与槽
Qt谈到信号,涉及三个要素:
信号源:由哪个控件发出信号。
信号的类型:用户进行不同的操作,可能触发不同的信号。(比如点击按钮,触发点击信号。在输入框中移动光标,触发移动光标信号)
信号的处理方式:槽(slot)就是特殊函数(用connect这样的函数把一个信号与一个槽关联起来,后续只要信号触发了,Qt会自动执行槽函数)
所谓的"槽函数"本质是一种"回调函数",比如:其中handleClick就是回调函数,把方法(函数)传进去,根据方法(函数)处理信号。
cpp
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick);
回忆一下回调函数:C++中的operator()中自定义比较的方法。Linux中信号处理函数,如何去处理信号。
connect是QOject提供的静态的函数成员:所以其它控件都能使用connect

Qt函数原型:
cpp
connect (const QObject *sender,
const char * signal ,
const QObject * receiver ,
const char * method ,
Qt::ConnectionType type = Qt::AutoConnection )

简单来说:第一个参数是谁发出信号,第二个参数是什么信号,第三个参数是谁去处理信号,第四个参数是如何处理信号。
例子
窗口上有一个按钮,点击按钮关闭:
cpp
#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("关闭");
connect(button,&QPushButton::clicked,this,&Widget::close);
}
Widget::~Widget()
{
delete ui;
}

在该函数中clicked是信号(Signal),close是槽(Slot),信号通知有事件发生,槽就是槽是响应信号的函数。
问题:我们如何找到QPushButton有个clicked信号?如何找到QWidget有一个close槽?
答:多看文档。
在翻阅文档时,若在当前类中没有找到对应的线索,去看其的父类:
比如文档中QPushButton里没有clicked,但QPushButton继承了QAbstractButton:

点击clicked能看到详细说明:

查阅文档中的信号,最重要的是关注信号的发送时机。(用户进行了什么样的操作,能够产生该信号)
问题:为什么void (*)() 能当成char *用呢》

Qt5之前,connect是这样传参的:
cpp
connect(button, SIGNAL(clicked()), this, SLOT(close()));
用到了#操作符:
例子:#a 是 C/C++ 的字符串化操作符,它把宏参数变成字符串字面量
cpp
#define SIGNAL(a) #a
#define SLOT(a) #a
// #a 的效果:无论a的类型是什么,都会变成char*
SIGNAL(clicked()) → "clicked()"
SLOT(close()) → "close()"
问:为什么不用函数去转成char*?
答:如果用函数去转,代码是写死的,比如return "close()"是写死的,只能返回 "close()",#可以做到按需生成,用户传入什么函数签名,就生成对应的字符串,灵活性提高。
在Qt 5开始,对上述写法做出了简化,给connect提供了重载版本,第二个参数和第四个参数变成了泛型参数,允许传入任意类型的指针函数:

并且connect函数带有一定的参数检查功能,如果传入的第一个参数和第二个参数不匹配,或者第三和第四个参数不匹配,代码编译出错。
自定义信号与槽
上面的例子是Qt自己内置的,有时自己的需求在Qt中是没有的,就需要自定义信号与自定义槽。
自定义槽:一个普通的自定义函数。
第一种定义槽函数的方法,例子:

在以前的Qt中,槽函数必须放到public/private/protected slots:

此处slots是Qt自己扩展的关键字(不是C++标准中的语法),因为Qt里广泛使用元编程(基于代码,生成代码),qmake构建Qt项目的时候,会调用专门的扫描器,扫描到特定的关键字(比如slots...),基于关键字自动生成一大堆相关的代码。
第二种定义槽函数的方法,例子:把Push Button拖到界面上,右键后点击转到槽-》点击clicked()-》点确定

就会生成函数:


我们发现没有用到connect,说明除了通过connect来连接信号槽外,还可以通过函数名字的方式来连接:符合下述规则后,Qt自动的把信号和槽建立上联系

如果我们将名字进行更改再运行,他就不会有效果:

应用程序会输出提示:

综上所述:
如果我们通过图形化界面创建控件,推荐使用这种快速方式来连接信号槽。
如果通过代码方式创建控件,还得手动connect。
自定义信号
实际开发中,很少会需要自定义信号,因为在GUI中,用户能够进行哪些操作,是可以穷举的,Qt 的内置信号,基本覆盖了上述所有可能的用户操作。
自定义信号有以下两点特点:
1.信号是一类非常特殊的函数,程序员只需要写出函数声明,并且告诉Qt ,这是一个"信号"即可。
这个函数的定义,是由Qt在编译的过程中,自动生成的(程序员无法干预)。
2.作为信号函数,这个函数的返回值必须是void类型。
用到Qt 自己扩展的关键字:

在 Qt 项目构建过程中,moc(元对象编译器)会扫描包含 Q_OBJECT 宏的头文件。当检测到signals: 关键字时,它会将此区域内的函数声明识别为信号,并自动为这些信号生成对应的函数实现。
widget.h:
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handleMysingal();
signals:
void mySignal();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(this,&Widget::mySignal,this,&Widget::handleMysingal);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleMysingal()
{
this->setWindowTitle("处理自定义信号");
}
我们发现并没有触发信号:

问题:如何才能触发出自定义信号?
答:Qt 内置的信号,都不需要手动通过代码触发。用户在GUI进行操作时,会自动触发对应的信号(发射信号的代码已经内置到 Qt的框架中了)想手动发射自定义信号,通过emit 信号();发射

不仅可以在构造函数中写,也可以在处理函数中写:

过程:

Qt 5中emit啥都没做,真正的操作包含在mySignal内部生成的函数定义,即使不写emit,信号也能发出去:

实际开发在,建议加上emit,增加可读性,并且自定义的信号99%都是通过emit才能触发。
带参数的信号与槽
当信号带有参数时,从信号的第1个参数开始,与槽的参数类型必须匹配或兼容,数量可以不一致,但信号的参数数量≥槽的参数数量。
这样在发射信号的时候,就可以给信号函数传递实参,与之对应的这个参数会传递到对应的槽函数中。
widget.h:

widget.cpp:


Qt中很多内置的信号,也带有参数,比如:是复选框,就是性别的二选一

问题:为什么要求信号的参数≥槽的参数?
答:一个槽函数,可能会绑定多个信号,若严格要求参数一个,意味着信号绑定槽的要求变高了。
还有个重要的知识点:
Qt中如果要让某个类能够使用信号槽,必须在类最开始的地方,写下Q_OBJECT宏:

进一步展开:(不用过多关注,能使用即可)

谈一谈信号与槽
在其它的GUI开发框架中,搞得都要简洁一些:一个事件只能对应一个函数
cpp
button.onclick = handle;
function handle(){
......
}
而Qt 信号槽,connect这个机制能做到:
1.解耦合:把触发用户操作的控件与处理对应用户的操作逻辑 解耦合。
2.多对多:一个信号,可以connect到多个槽函数上;一个槽函数,也能被多个信号connect。
信号与槽断开连接
disconnect可以断开信号与槽的连接。
示例:
widget.h:
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handleCliked();
void handleCliked2();
private slots:
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleCliked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleCliked()
{
this->setWindowTitle("木有修改");
}
void Widget::handleCliked2()
{
this->setWindowTitle("修改窗口喽");
}
void Widget::on_pushButton_2_clicked()
{
//断开原有链接
disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleCliked);
//绑定新的槽函数
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleCliked2);
}
效果:

disconnect用的比较少,大部分情况下,把信号与槽连上之后,就不管了,只有主动断开信号绑到另一个槽函数上才会用到。
使用lambda表达式定义槽函数
例子:

如果我们想点击按钮后,按钮会换个位置时,会发现报错:

因为lambda是一个回调函数,这个函数无法直接获取到上层作用域中的变量。
为了解决问题,引入"变量捕获"语法从外层作用域中获取到变量:

也可以捕获多个变量:

还可以写成[=],表示把上层作用域中所有的变量名都捕获进来:

注意:因为不知道什么时候使用回调函数,所以要确保变量的生命周期"存活时间"。
lambda是C++11引入的,对于Qt4或者更老的版本,需要手动在.pro文件上加上C++11的编译选项:

常用控件
编程是站在"巨人的肩膀上",而不是"从头造轮子"。
Qt中提供了很多内置的控件(按钮、文本框、单选按钮...)拿来直接用。
Qt Designer左侧这一长条,就是Qt给我们内置好的控件:

QWidget
Qt 中的各种控件都是继承自QWidget类。
点击右侧界面能看到QWidget的各种属性,也可以在这里直接编辑:

enabled
enabled描述了一个控件是否处于"可用"状态。相对概念为"禁用"。
"禁用"指的是该控件不能接收任何用户的输入事件,并且外观上是灰色的。
如果一个widget被禁用,则该widget的子元素也被禁用。
| API | 说明 |
|---|---|
| isEnabled() | 获取到控件的可⽤状态. |
| setEnabled | 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤. |
示例:可用清楚看到,按钮灰了,也无法按下。

示例用的图形化:点击按钮,有日志出现;点击切换状态,导致按钮变灰色无法使用,再次点击可恢复
cpp
#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()
{
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,也可以分四个属性单独设置. |
Qt中针对几何上的概念进行了封装:

这样在C++中使用上述对象,可用根据值传参。(传参涉及到了拷贝,若对象过大,通常通过传引用的方式。对象小了,直接传值)
示例:用下面4个键位控制上面的Target移动

第一阶段,先写UP方向:

发现点击UP之后只有日志触发,Target并没有移动,因为改变的是rect,不是Target,要把修改后的rect设置进Target中:

我们发现他Y轴变的同时块的高度(height)也变了。我们不想让块的大小发生改变,而是平移。
解决办法:不再修改QRect,通过QRect基于setGeometry第二个版本的函数重新设置位置即可。

这样就成了,补全所有方向:
cpp
#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_UP_clicked()
{
//获取Target的geometry
QRect rect = ui->pushButton_Target->geometry();
qDebug() << 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;
ui->pushButton_Target->setGeometry(rect.x(),rect.y()+5,rect.width(),rect.height());
}
void Widget::on_pushButton_right_clicked()
{
QRect rect = ui->pushButton_Target->geometry();
qDebug() << rect;
ui->pushButton_Target->setGeometry(rect.x()+5,rect.y(),rect.width(),rect.height());
}
void Widget::on_pushButton_left_clicked()
{
QRect rect = ui->pushButton_Target->geometry();
qDebug() << rect;
ui->pushButton_Target->setGeometry(rect.x()-5,rect.y(),rect.width(),rect.height());
}
window frame的影响

用代码看一下区别:我们发现日志中边框是一样的,这是因为这个代码放在构造函数中Widget对象正在构造,没放到window frame中,导致window frame的框和widget的框一样

因此放到更迟一点的环境即可。
比如我创建个按钮:会发现正如上述所说,window frame比widget大

windowTitle
| API | 说明 |
|---|---|
| windowTitle() | 获取到控件的窗⼝标题。 |
| setWindowTitle(const QString& title) | 设置控件的窗⼝标题。 |
windowTitle属性属于QWidget类,它主要对窗口(顶层控件)有意义。对于非窗口的控件设置此属性通常没有可见效果,除非该控件后来被提升为独立窗口。
例子:按钮并没有改变窗口

windowIcon
windowIcon 表示窗口的图标。
下面说明中QIcon类表示一个图标,且两个API类似于windowTitle,只能针对顶层窗口使用。
| API | 说明 |
|---|---|
| windowIcon() | 获取到控件的窗⼝图标. 返回QIcon对象。 |
| setWindowIcon(const QIcon&icon) | 设置控件的窗⼝图标。 |
windows的图标是我们常见的:

这是Qt的图标:

在用代码之前要在本地选择一个图片,加载过来,比如:路径是不能带中文的


我们发现一个问题:我们发现QIcon 创建的时候没用指针?我们平时创建的比如QPushButton都应该是指针啊?
答:QPushButton推荐用堆来创建对象,而QIcon是通过栈来创建对象。
至于为什么,我是这么想的:QIcon 自身是一个比较小的对象,它不支持对象树,也不能有父子类型,实际中源码类似是:
cpp
// QWidget包含QIcon数据
class QAbstractButton : public QWidget
{
private:
QIcon icon; // 普通成员变量,不是指针
QString text; // 普通成员变量
// 这些是数据成员,不是子对象
};
并且QIcon的功能是从代码编译后就确定下来的(图像是啥样就啥样),而QPushButton这种需要在代码运行后也会有所改变,若是在栈上,QIcon不变,所以释放了无所谓。若QPushButton在栈上,释放了功能也就没了,所以要跟着整个树去释放等操作。
遇到的小问题:我们复制下来的图片路径是 \ ,而我们C++中 \ 表示转义,所以要用到 / 。
如果非要用 \ ,C++11引入了raw string 解决上述问题,让字符串中不包含任意转义字符:

遗留的问题:使用绝对路径是不科学,我们写的程序是要发给用户的电脑上,无法保证,我们开发机和用户机的图片路径一样,所以要使用相对路径。
但是,使用相对路径得保证发过去的图片相对对于文件的相对位置不能变,用户一旦变了又不能用了。
于是Qt有了qrc机制,从根本上解决了上述的问题:
给Qt 项目引入了一个额外的 xml 文件(后缀名使用.qrc),在这个xml 中把要使用的图片资源导入进来,并在xml 中进行记录。
Qt 在编译项目的时候,会根据qrc 中描述的图片信息,找到图片内容,提取出图片的二进制数据,再把这些二进制数据转成C++代码,最终编译到exe中。所以就有了缺点:无法导入太大的资源文件,比如几个GB的视频文件。
qrc文件资源管理
qrc的使用方式:
1.在项目中创建一个qrc文件:是创建文件,不是创建项目

文件名随便起,不能用中文名,后缀他会自己加上:


2.把图片导入到这个resource.qrc文件中:
先创建一个"前缀"(Prefix),所谓的"前缀",可用理解成虚拟的目录,这个目录没有在我们的电脑上,是Qt自己抽象出来的。

然后把刚才使用的picture.jpg 这个图片导入到 资源文件中:
"添加文件"按钮在创建prefix 之前是禁用的,创建好prefix之后就能使用了,添加文件就是添加到prefix下面的,我这里是添加到 / 下:

点击"添加文件":就会发现跳转到本项目路径下

如果我们强行选择picture.jpg 目前所在的路径:就会报错

这是因为导入图片的时候,需要确保导入的图片必须在resource.qrc 文件的同级目录,或者同级目录中的子目录:

导入成功的效果:


效果:

我们查看Debug文件夹:qrc中导入的图片资源,就会被转成这个 qrc_resource.cpp

里面的内容:里面的字节内容就是 picture.png 里的每个字节的数据

当Qt 项目进行编译时,这个cpp文件就一起被编译到exe中。
windowOpacity
跟透明度有关。
| API | 说明 |
|---|---|
| windowOpacity() | 获取到控件的不透明数值。返回float,取值为0.0 ~ 1.0,其中0.0表⽰全透明,1.0表⽰完全不透明。 |
| setWindowOpacity(float n) | 设置控件的不透明数值。 |
示例:
cpp
#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_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);
}
效果:一直点 "-" 会消失

第一个问题:代码中的透明度减少的幅度是0.1,发现日志的减少,并非规律,有误差

答:涉及到浮点数在内存中的存储,IEEE 754标准规定使用二进制科学计数法,想要详细了解可用看王道计算机考研的讲解
简单说一下,二进制小数中,第一个有效数字表示0.5,第二个是0.25,第三个0.125...这样分下去凑不出0.1。
所以平时写代码基本看不到0.1 + 0.2 == 0.3这种判断,都是作差看绝对值是否小于预期的误差范围。
第二个问题:上述代码中,这里加了判断条件,不加也可以跑通,超过1.0 的数字设置不进去(setWindowOpacity内部也进行了判断)

这个判定最好写上,在《代码大全》中详细的讨论了代码的规范,其中的"防御性编程",描述的是别人犯错,不会对自身构成太大的伤害。
cursor
修改鼠标光标的样式。
| API | 说明 |
|---|---|
| cursor() | 获取到当前widget的cursor属性,返回QCursor对象。当⿏标悬停在该widget上时,就会显⽰出对应的形状。 |
| setCursor(const QCursor& cursor) | 设置该widget光标的形状.仅在⿏标停留在该widget上时⽣效。 |
| QGuiApplication::setOverrideCursor(const QCursor&cursor) | 设置全局光标的形状。对整个程序中的所有widget都会⽣效。覆盖上⾯的setCursor设置的内容。 |
其中cursor()、setCursor(const QCursor& cursor)是Widget级别的,同一个界面中,不同的控件可以设置成不同的光标。
QGuiApplication::setOverrideCursor(const QCursor&cursor) 设置全局的光标(程序内部的全局,不是系统级别的全局)。
通过图形化去改变鼠标光标:选择光标样式

效果:

代码:
cpp
#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,可以看见各种光标的类型:

Qt 允许我们通过自定义的图片来设置光标:
先准备一个图片,把图片导入到项目在(qrc 管理),在代码中访问到这个图片,基于这个图片构造出光标对象并设置。
这里要用QPixmap 去存储图片。
QPixmap与QIcon的区别
| 特性 | QPixmap | QIcon |
|---|---|---|
| 本质 | 具体的图像数据 | 图标的抽象封装 |
| 状态支持 | 单一状态 | 多状态(正常、禁用、激活等) |
| 使用场景 | 绘图、图像处理 | 界面组件图标 |
| 尺寸 | 固定尺寸 | 多尺寸(预置多个专门设计的不同尺寸版本,运行时根据需求选择最接近的版本) |
两者也可以相互转换:
cpp
// QPixmap → QIcon
QPixmap pixmap("image.png");
QIcon icon(pixmap);
// QIcon → QPixmap(获取特定状态和尺寸的pixmap)
QIcon icon("icon.png");
QPixmap pixmap = icon.pixmap(32, 32); // 获取32x32的pixmap
QPixmap disabledPixmap = icon.pixmap(32, 32, QIcon::Disabled);
自定义光标代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//访问到图片文件
QPixmap pixmap(":/picture.png");
// 构造光标对象
QCursor cursor(pixmap,10,10);
// 把光标设置进去
this->setCursor(cursor);
}
Widget::~Widget()
{
delete ui;
}
发现光标的图像太大了:

pixmap提供了scaled()方法,可以进行缩放:
cpp
pixmap = pixmap.scaled(50,50); //不是修改对象本身,而是返回新的图片对象副本
效果:可以看到小了很多

还有个关于cursor参数的问题:

font
跟字体相关的内容:
| API | 说明 |
|---|---|
| font() | 获取当前widget的字体信息,返回QFont对象。 |
| setFont(const QFont& font) | 设置当前widget的字体信息。 |
QFont:
| API | 说明 |
|---|---|
| family | 字体家族,⽐如"楷体","宋体","微软雅⿊"等。 |
| pointSize | 字体⼤⼩ |
| weight | 字体粗细。以数值⽅式表⽰粗细程度取值范围为[0,99],数值越⼤,越粗 |
| bold | 是否加粗,设置为true,相当于weight为75。设置为false相当于weight 为50。 |
| italic | 是否倾斜 |
| underline | 是否带有下划线 |
| strikeOut | 是否带有删除线 |
用图形化界面:font中直接调节,有实时性

代码演示:

如果我们想借鉴其它网页的字体可以:鼠标右键


toolTip
一个GUI 程序,界面比较复杂,按钮啥的很多,当我们把鼠标悬停到某个控件上时,就能弹出一个提示。
| API | 说明 |
|---|---|
| setToolTip | 设置toolTip,⿏标悬停在该widget上时会有提⽰说明。 |
| setToolTipDuring | 设置toolTip提⽰的时间。单位ms,间到后toolTip⾃动消失。 |
代码:
cpp
#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); //单位是毫秒
ui->pushButton_no->setToolTip("这是一个 no 按钮");
ui->pushButton_no->setToolTipDuration(3000);
}
Widget::~Widget()
{
delete ui;
}
效果:

focusPolicy
设置控件获取到焦点的策略。
焦点:当我们百度搜索的时候,必须点击输入框,才能输入,若在点击输入框之后,点击其它地方,就是失去焦点。

| API | 说明 |
|---|---|
| focusPolicy() | 获取该widget的focusPolicy,返回Qt::FocusPolicy。 |
| setFocusPolicy(Qt::FocusPolicy policy) | 设置widget的focusPolicy。 |

主要是图形化使用:比如我选了TabFocus

效果:只有按Tab才能选定,鼠标无法选定

styleSheet
通过QSS(CSS的模仿)设置widget样式(界面的样子)。
Qt Designer中设计:


里面的键值对在Qt文档中会有介绍,或者直接在Qt 文档中搜索 Qt Style Sheet。
通过代码设置样式:实现一个''夜间模式'功能'
首先设置一个文本框和两个按钮:

cpp
#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:white;");
//设置文本框的样式
ui->plainTextEdit->setStyleSheet("background-color:white;color:black");
//设置按钮的样式
ui->pushButton_light->setStyleSheet("color:black");
ui->pushButton_evening->setStyleSheet("color:black");
}
void Widget::on_pushButton_evening_clicked()
{
//设置窗口的样式
this->setStyleSheet("background-color:black;");
//设置文本框的样式
ui->plainTextEdit->setStyleSheet("background-color:black;color:white");
//设置按钮的样式
ui->pushButton_light->setStyleSheet("color:white");
ui->pushButton_evening->setStyleSheet("color:white");
}
效果:

我们发现,点完"日间模式"的下面的边和初始的边颜色不一样,这里说一下解决办法:
在计算机中,使用RGB的方式表示颜色。(三原色混合:red、green、blue)
分别用一个字节表示R,一个字节表示G,一个字节表示B,分量是0~255,rgb(255,0,255)表示红蓝拉满,没绿色。
用QQ的截图工具可以看到颜色的量:我们可以看出是rgb(243,243,243)

自定义颜色比例就行:

什么时候用ui->,什么时候用this->
看到.ui文件中的控件 → 用ui->。
看到自己代码中声明的变量/方法 → 用this->。