Qt (信号与槽 Widget控件 qrc文件)

文章目录

信号与槽

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->。

相关推荐
我要打打代码2 小时前
C# 各种类库
开发语言·c#
小辰辰就要混2 小时前
20、Lambda表达式和Stream
开发语言·python
Vivienne_ChenW2 小时前
Apollo 配置中心核心用法(实战版)
java·开发语言·分布式·阿里云·产品运营
小乔的编程内容分享站2 小时前
C语言函数的声明和定义(文章包括当VScode中含多个.c文件且含.h文件如何同时编译
c语言·开发语言·vscode
郝学胜-神的一滴2 小时前
跨平台通信的艺术与哲学:Qt与Linux Socket的深度对话
linux·服务器·开发语言·网络·c++·qt·软件构建
小龙报2 小时前
【数据结构与算法】指针美学与链表思维:单链表核心操作全实现与深度精讲
c语言·开发语言·数据结构·c++·物联网·算法·链表
杜子不疼.2 小时前
【Linux】库制作与原理(一):静态库的制作与使用
linux·运维·服务器·开发语言
野犬寒鸦3 小时前
从零起步学习并发编程 || 第四章:synchronized底层源码级讲解及项目实战应用案例
java·服务器·开发语言·jvm·后端·学习·面试
£漫步 云端彡3 小时前
Golang学习历程【第十一篇 接口(interface)】
开发语言·学习·golang