当前位置: 首页 > article >正文

初识Qt · 信号与槽 · 自定义和参数

目录

前言:

自定义槽

自定义信号

参数

connect小结


前言:

目前接触到的函数是connect,当我们使用的时候,我们发现connect关联的信号和槽,即便是函数,也是Qt中已经存在的,即内置函数,那么我们是否能够自己自定义信号或者说是自己自定义槽函数呢?

当然是可以的。

其实这么说都有点废话了,应该槽函数我们已经自定义了,对于内置槽函数我们也看过了,即锯齿状的是槽函数,波纹状的是信号。

那么本文,我们将来学习,如何自定义。


自定义槽

假定我们现在实现一个功能就是,点击按钮,会使得widget的标题发生改变,那么自然使用connect函数,在前面我们也介绍过槽函数必须放在public slot中,就像:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    
public slots:
    void Headle();

private:
    Ui::Widget *ui;
    QPushButton* button;
};

但是实际上现在Qt5版本和6版本是不用这样写的了。我们直接给它当成正常的成员函数就可以了。

对于slots关键字来说,它是Qt中自己扩展的关键字,并不是C++中的标准语法,而在Qt中广泛使用了元编程技术,所以qmake在构建Qt项目的时候,就会专门扫描这种关键字,用来代码生成代码,不过现在似乎用不着这个关键字了~

这是一种自定义槽函数的方式。

我们现在在UI界面定义出一个pushbutton,使用第二种定义槽函数的方式:

就这两步,我们就已经成功生成了一个自定义的槽函数:


void Widget::on_pushButton_clicked()
{
    
}

这个时候你看命名也是非常形象的,on,在哪里控件上面,pushButton,代表控件的objectname,clicked代表的是发出的信号。

所以Qt在这里的命名是非常nice的~其中这个on一般是前缀。


自定义信号

Qt不仅支持自定义槽函数,也支持自定义信号,但是实际上呢,Qt的自定义信号在开发中用的是非常少见的,因为在GUI界面中,用户能执行的操作咱们都是可以穷举出来的。

比如给你一个光标,你能对它执行的操作无非就是移动,点击,所以自定义信号实际上那么必要。但是我们还是简单学习一下~

对于信号来说,它是一个非常非常特殊的函数:

1.不需要自己实现定义

2.只需要写声明

3.返回值只能是void

4.参数没有要求,可以支持重载

5.需要使用signals关键字

首先,为什么不需要自己实现定义呢~因为这个函数的定义是Qt在qmake的过程中自己编译的,不需要程序员去干预,也不能让程序员去干预,因为你自定义了个信号,本身配合Qt整体的框架就是一个麻烦事儿,毕竟需要做既定的操作,所以定义方面,我们不能干预。

剩下的就是对于函数本身的要求了,简单来说就是这样:

class Widget : public QWidget
{
    Q_OBJECT

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

signals:
       void MySignal();
};

使用的时候仍然使用connect函数,但是问题来了,我们如何发出该信号呢?

这里使用到的就是一个关键字了,emit,虽然但是不适用该关键字也是没事儿的

以下是一个示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* button = new QPushButton(this);
    emit MySignal();
    connect(this, &Widget::MySignal, this,&Widget::on_pushButton_clicked);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{
   this->setWindowTitle("Hello qt!");
}

点击按钮之后的效果就是这样。

当然了,自定义信号可以在任意位置发送,不一定要在构造函数里面发送,并且,我们可以不使用emit关键字,这个东西使用起来没有啥用。


参数

对于信号和槽来说是可以带参数的, 毕竟在上文我们就提及到了,自定义信号是可以构成重载的。

当槽和信号被绑定在了一起之后,这两个函数的参数应该是大致一致的

至于为什么是大致一致,这里留一个伏笔~

首先,我们不妨先见见:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    
public slots:
    void HandSig(const QString&);
    
signals:
    void mysignal(const QString&);   
    

private:
    Ui::Widget *ui;
};

先自定义出我们的信号和槽函数,在Qt这里的参数是可以不用写变量名的,笔者依稀记得在C++函数声明似乎也是这样~

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(this, &Widget::mysignal, this, &Widget::HandSig);
    mysignal("Hello Qt!!");
}

Widget::~Widget()
{
    delete ui;
}

void Widget::HandSig(const QString &text)
{
    this->setWindowTitle(text);
}

此时窗口刚刚运行Title就会变成Hello Qt了。

那么如果我这样修改一下:

void mysignal(const QString&, int);
   mysignal("Hello Qt!!",12);

你会发现运行结果是一摸一样的,这就是为什么我说是大致一致即可,这个的意思是指:

信号的参数个数应该大于等于槽的参数个数

这是Qt中的一个非常特别的点。

好了,让我们回到最开始的点:

class Widget : public QWidget
{
    Q_OBJECT

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

public slots:
    void HandSig(const QString&);

signals:
    void mysignal(const QString&, int);


private:
    Ui::Widget *ui;
};

对于Qt中的类想要使用信号槽的这个机制,即能在类中定义槽函数和信号,就必须要在类最开始的地方写这个宏。

当然,这个宏我们暂时先不研究,这是我们现阶段研究不上来的。 


connect小结

对于connect来说,或者说信号和槽的这个机制,在所有的GUI开发框架中是一个非常特殊的存在.比如在网页开发中,相应用户的操作非常简单,使用回调函数就可以了,不像connect函数,虽然能一对多吧~但是现在看来好像不太行了?

因为Qt最开始的时候,一个最大的卖点就是connect,一个信号可以关联到多个槽函数,但是现在实际上很少有这样操作的,毕竟A信号关联了B C两个槽函数之后,万一触发了这个B,C也触发的同时给系统带崩溃了呢?

所以Qt最开始的设想实际上是想让信号和槽解耦合,实现一个低耦合,高内聚的一个特点

比如网页开发,一个事件对应一个处理函数,Qt想多对多,就像数据库的关联表一样~

但是现在好像,这个卖点不太行了。

当然了,Qt中还有很多值得我们去学习的点,不能只抓住这个多对多的点不妨,即便现在一对一就够用了,但是当时Qt的这个特点可是非常nb的了。

就像这样:、

class Widget : public QWidget
{
    Q_OBJECT

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

signals:
    void mySignal1();
    void mySignal2();
    void mySignal3();

public slots:
    void mySlot1();
    void mySlot2();
    void mySlot3();

private:
    Ui::Widget *ui;
};
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(this, &Widget::mySignal1, this, &Widget::mySlot1);
    connect(this, &Widget::mySignal1, this, &Widget::mySlot2);
    connect(this, &Widget::mySignal2, this, &Widget::mySlot1);
    connect(this, &Widget::mySignal2, this, &Widget::mySlot3);
}
Widget::~Widget()
{
    delete ui;
}

void Widget::mySlot1()
{
    qDebug() << "mySlot1";
}
void Widget::mySlot2()
{
    qDebug() << "mySlot2";
}

void Widget::mySlot3()
{
    qDebug() << "mySlot3";
}

感谢阅读!


http://www.kler.cn/a/572769.html

相关文章:

  • 自然语言处理:文本分类
  • CS144 Lab Checkpoint 5: down the stack (the network interface)
  • Element UI-Select选择器结合树形控件终极版
  • Ruby爬虫如何控制并发数量:爬取京东电子产品
  • 如何在matlab中创建自己的库
  • CSS【实战】模拟 html 的 title 属性(鼠标悬浮显示提示文字)
  • OBOO鸥柏丨LCD液晶室外AI触控屏广告一体机,服务区交互新趋势
  • python:pymunk + pygame 模拟六边形中小球弹跳运动
  • 文件上传漏洞:upload-labs靶场11-20
  • RISCV下Dovetail移植(2)——原子操作
  • TikTok矩阵系统介绍
  • 特辣的海藻!8
  • @PostConstruct注解的作用
  • 【前端学习笔记】Git 原理及面试题
  • 用本地浏览器打开服务器上使用的Tensorboard
  • 自学微信小程序的第十三天
  • 【Spring Boot 应用开发】-04-02 自动配置-数据源-手撸一个最简持久层工具类
  • 驱动开发系列43 - Linux 显卡KMD驱动代码分析(四)- DRM设备操作
  • Golang的数据库分库分表
  • 【网络安全】API安全防护完整指南