zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Qt5开发从入门到精通——第一篇(概述——(信号和槽机制)、(原对象系统)、(布局管理器))

对象系统入门开发 机制 布局 精通 概述
2023-09-27 14:19:51 时间

欢迎小伙伴的点评✨✨,相互学习、互关必回、全天在线🍳🍳🍳
博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩‍🚀


前言

本章节会探讨三个开发步骤、如下所示:

  • 信号和槽机制
  • 原对象系统
  • 布局管理器

一、 信号和槽机制

Qt 提供了信号和槽机制用于完成界面操作的响应,信号和槽机制是完成任意两个 Qt 对象之
间的通信机制。其中,信号会在某个特定情况或动作下被触发,槽是等同于接收并处理信号的函
数。例如,若要将一个窗口部件的变化情况通知给另 一个窗口部件,则一个窗口部件发送信号,
另一个窗口部件的槽接收此信号并进行相应的操作,即可实现两个窗口部件之间的通信 。 每个 Qt
对象都包含若干个预定义的信号和若干个预定义的槽 。 当某一个特定事件发生时,一个信号被发
送,与信号相关联的槽则会响应信号并完成相应的处理 。 当 一个类被继承时,该类的信号和槽也
同时被继承,也可以根据需要自定义信号和槽 。

1.1信号与槽机制的连接方式

(1)一个信号可以与另一个信号相连,代码如下:

connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal1));

表示Object1的信号1发送可以触发Object2的信号1发送

(2)同一个信号可以与多个槽相连,代码如下:

connect(Object1,SIGNAL(signal2),Object2,SIGNAL(slot2));
connect(Object1,SIGNAL(signal2),Object3,SIGNAL(slot1));

(3)同一个槽可以相应多个信号,代码如下:

connect(Object1,SIGNAL(signal2),Object2,SIGNAL(slot2));
connect(Object3,SIGNAL(signal2),Object2,SIGNAL(slot2));

但是,常用的连接方式为:

connect(Object1,SIGNAL(signal),Object2,SLOT(slot));

其中, signal 为对象 Objectl 的信号, slot 为对象 Object2 的槽。

(4)信号与槽机制的SIGNAL()和SLOT()解析:

SIGNAL()和 SLOT()是 Qt 定义的两个宏,它们返回其参数的 C 语言风格的字符串 (const
char*) 。因此,下面关联信号和槽的两个语句是等同的:

connect(button,SIGNAL(clicked()), this, SLOT (showArea ()));
connect (button, "clicked()",this, "showArea() ");

1.2信号与槽机制的优点

(1) 类型安全。
需要关联的信号和槽的签名必须是等同的,即信号的参数类型和参数个数
与接收该信号的槽的参数类型和参数个数相同。不过,一个槽的参数个数是可以少千信号的参
数个数的,但缺少的参数必须是信号参数的最后一个或几个参数。如果信号和槽的签名不符,
编译器就会报错。

(2)松散耦合。

信号和槽机制减弱了 Qt 对象的耦合度。激发信号的 Qt 对象无须知道是哪
个对象的哪个槽需要接收它发出的信号,它只需做的是在适当的时间发送适当的信号就可以了,
而不需要知道也不关心它的信号有没有被接收到,更不需要知道是哪个对象的哪个槽接收到了
信号。同样,对象的槽也不知道是哪些信号关联了自己,而一旦关联信号和槽, Qt 就保证了适
合的槽得到了调用。即使关联的对象在运行时被删除,应用程序也不会崩溃。
一个类若要支待信号和槽,就必须从 QObject 或 QObject 的子类继承。注意, Qt 信号和槽
机制不支持对模板的使用。

1.3信号与槽机制的效率

信号和槽机制增强了对象间通信的灵活性,然而,这也损失了一些性能。同回调函数相比,
信号和槽机制运行速度有些慢。通常,通过传递一个信号来调用槽函数会比直接调用非虚函数
的运行速度慢 10 倍。主要原因如下。

(1) 需要定位接收信号的对象。
(2)安全地遍历所有的关联(如一个信号关联多个槽的情况)。
(3)编组(marshal)/解组(unmarshal)传递的参数。
(4)在多线程时,信号可能需要排队等待。

然而,与创建堆对象的 new 操作及删除堆对象的 delete 操作相比,信号和槽的运行代价
很小。信号和槽机制导致的这点性能损失对实时应用程序是可以忽略的;同信号和槽提供的
灵活性和简便性相比,这点性能损失也是值得的。

二、原对象系统

QtS 元对象系统提供了对象间的通信机制(信号和槽)、运行时类型信息和动态属性
系统的支待,是标准 C++的一个扩展,它使 Qt 能够更好地实现 GUI 图形用户界面编程。
QtS 的元对象系统不支持 C++模板,尽管该模板扩展了标准 C++ 的功能。但是,元对象
系统提供了模板无法提供的一些特性。 QtS 元对象系统基千以下三个事实。

(1)基类QObject:

任何需要使用元对象系统功能的类必须继承自QObject

(2)Q_OBJECT宏:

Q_OBJECT 宏必须出现在类的私有声明区中,用千启动元对象的特性。

(3)元对象编译器(Meta-Object Compiler,moc):

为QObject 子类实现元对象特性提供必要的代码实现。

三、布局管理器

在设计较复杂的 GUI 用户界面时,仅通过指定窗口部件的父子关系以期达到加载和排列窗
口部件的方法是行不通的,最好的办法是使用 Qt 提供的布局管理器。

QGridLayout *mainLayout=new QGridLayout(this);     //(a)
mainLayout->addWidget(label1,0,0); 				   //(b)
mainLayout->addWidget(lineEdit,0,1);
mainLayout->addWidget(label2,1,0);
mainLayout->addWidget(button,1,1);
setLayout(mainLayout);                             //(c)

其中,
(a)QGridLayout *mainLayout=new QGridLayout(this): 创建一个网格布局管理器对象mainLayout, 并用 this 指出父窗口。

(b) mainLayout->addWidget(…):分别将控件对象 labell 、 lineEdit 、 label2 和 button 放置在布局管理器中,还可以在创建布局管理器对象时不必指明父窗口。

(c) QWidget:":setLayout(…):将布局管理器添加到对应的窗口部件对象中。因为这里的主窗口就是父窗口,所以直接调用 setLayout(mainLayout)即可。


四、代码实例

4.1、widget.h 原码分析

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QDebug>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
          

private:
    Ui::Widget *ui;
    QPushButton *button;        //声明一个QPushButton类型的指针
    QLineEdit *LineEdit;        //声明一个QLineEdit类型的指针
private slots:
     void button_on();          //声明一个函数用于:button按钮触发连接用的槽
};

#endif // WIDGET_H

4.2、widget.h 原码分析

#include "widget.h"
#include "ui_widget.h"
#include <QGridLayout>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    button = new QPushButton("信号与槽");       //初始化button指针,分配空间
    LineEdit = new QLineEdit;                 //初始化LineEdit指针,分配空间
    connect(button,SIGNAL(clicked(bool)),this,SLOT(button_on()));  //用于连接按钮信号与槽的触发
    QGridLayout *mainLayout = new QGridLayout;    //声明一个QGridLayout类型,并分配空间,用于画图

    mainLayout->addWidget(button,2,0);        //用画图指针设计按钮在窗口中的位置
    mainLayout->addWidget(LineEdit,1,0);



    setLayout(mainLayout);
}

Widget::~Widget()
{
    delete ui;
}
void Widget::button_on()
{
    LineEdit->setText("信号与槽连接成功");
    qDebug()<<1;
}

4.2、实际效果图

在这里插入图片描述