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

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript