QT的信号与槽

QT的信号与槽


文章目录

  • QT的信号与槽
  • 前言
  • 一、QT 打印"hello QT"的dome
  • 二、信号和槽机制?
  • 二、信号与槽的用法
    • 1、QT5的方式
      • 1. 无参的信号与槽的dome
      • 2.带参的信号与槽dome
    • 2、QT4的方式
    • 3、C++11的语法 Lambda表达式
      • 1、函数对象参数
      • 2、操作符重载函数参数
      • 3、可修改标示符
      • 4、错误抛出标示符
      • 5、函数返回值
      • 6、是函数体
    • 4.信号与槽的总结
    • 5.信号与槽的扩展
    • 6. 总结


前言

Qt的信号与槽是控件与控件进行交互的方式。是QT中比较重要的内容。


一、QT 打印"hello QT"的dome

#include <QApplication>
#include <QWidget>
int main(int argc, char *argv[])
{QApplication a(argc, argv);QWidget w;/* 创建一个窗口对象 创建对象会自动调用构造函数 */w.show(); /* 显示窗口 */w.setWindowTitle("hello QT"); /* 设置窗口标题 */return a.exec(); /* 一个程序能程序运行 一般都会用死循环 这里相当于while(1) 同时让程序一直执行,等待用户操作。等待事件的发生 比如鼠标,键盘事件*/
}

现在的操作都在主函数里操作如果代码一多就有点不合适了。在QWidget w 语句会自动调用QWidget的构造函数。放在构造里实现。后面所有的子控件都以这个窗口为中心来扩展。

下面在窗口里添加按钮控件。

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include <QPushButton>
class MainWidget : public QWidget
{Q_OBJECT
public:MainWidget(QWidget *parent = 0);~MainWidget();
private:QPushButton b1;  /* 在窗口类里定义按钮对象 */QPushButton *b2; /* 在窗口类里定义指针按钮对象 */
};
#endif // MAINWIDGET_H

mainwidget.cpp

MainWidget::MainWidget(QWidget *parent): QWidget(parent)
{b1.setParent(this);b1.setText("按钮1");b1.move(100, 100); /* 移动按钮的位置 默认0,0 */b2 = new QPushButton(this);b2->setText("按钮2");this->resize(400, 300); /* 设置窗口的大小 */
}

如上代码按钮有指定父对象。
指定父对象的两个方法:

  1. setParent(指定的父对象) b1.setParent(this)
  2. 调用构造函数是指定 b2 = new QPushButton(this)
    this就是当前窗口对象(MainWidget的对象)。

指定父对象的好处:

  1. Qt有一个机制就是指定父对象后不需要手动释放 new过的内存。
  2. 指定父对象后跟随父对象显示,不需要手动显示。

总结:要理解一个类的对象的创建过程才能更好的理解程序的执行顺序。(很重要)
当在一个类的成员中有类类型的成员变量指针时,在构造函数里申请空间。比如上面的 b2 = new QPushButton(this);

二、信号和槽机制?

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个点击信号(signal)。这种发出是没有目的的,类似广播。(任何控件都可以接收这个信号)如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。(这里提一句,Qt 的信号槽使用了额外的处理来实现,并不是 GoF 经典的观察者模式的实现方式。)

二、信号与槽的用法

首先信号与槽函数的连接都是通过connect函数来实现。总共有三种用法

1、QT5的方式

connect(&b1, &QPushButton::pressed, this, &MainWidget::close) /* b1按钮按下信号触发 窗口接收后关闭窗口  */

connect的参数
参数1:信号的发送者(指针类型)
参数2:信号 具体用法 &发送者类名::信号名
参数3:接收者(指针类型)
参数4:接受者接收到这个信号的处理 具体用法: &接收者类名::槽函数名
参数5:网络模块需要用到,这里先不介绍。

总结:上面的信号与槽都是系统的(系统已经定义好的)通过帮助文档就可以查找到。当然也可以自定义的。

1. 无参的信号与槽的dome

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QWidget>
#include <QPushButton>class MainWidget : public QWidget
{Q_OBJECTpublic:MainWidget(QWidget *parent = nullptr);~MainWidget();
signals:void signal_1(); /* 自定义一个信号 */public slots:void slot_Print(); /* 自定义槽函数 */void slot_cf();private:QPushButton *button;
};
#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include <QDebug>MainWidget::MainWidget(QWidget *parent): QWidget(parent)
{button = new QPushButton(this);button->setText("确定");button->move(100, 100);connect(button, &QPushButton::pressed, this, &MainWidget::slot_cf);connect(this, &MainWidget::signal_1, this, &MainWidget::slot_Print);
}MainWidget::~MainWidget()
{
}void MainWidget::slot_Print()
{qDebug()<< "接收到信号";
}void MainWidget::slot_cf()
{emit signal_1();
}

总结:自定义一个信号与自定义两个槽函数。按钮按下信号触发一个槽 slot_cf。接着在槽里发送自定义信号。接着触发另一个槽slot_Print打印 “接收到信号”。可以看到信号与槽都是没有参数的。

2.带参的信号与槽dome

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QWidget>
#include <QPushButton>class MainWidget : public QWidget
{Q_OBJECTpublic:MainWidget(QWidget *parent = nullptr);~MainWidget();
signals:void signal_1(); /* 自定义一个信号 */void signal_1(int data, QString str); /* 带参自定义一个信号 */public slots:void slot_Print(); /* 自定义槽函数 */void slot_Print(int data, QString str); /* 带参自定义槽函数 */void slot_cf();void slot_cf_1();private:QPushButton *button;QPushButton *button_1;
};
#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include <QtDebug>MainWidget::MainWidget(QWidget *parent): QWidget(parent)
{button = new QPushButton(this);button->setText("信号1");button->move(100, 100);button_1 = new QPushButton(this);button_1->setText("信号2");button_1->move(200, 200);connect(button, &QPushButton::pressed, this, &MainWidget::slot_cf);connect(button_1, &QPushButton::pressed, this, &MainWidget::slot_cf_1);/* 信号的函数指针 */void (MainWidget::*funSignal_1)() = &MainWidget::signal_1;void (MainWidget::*funSignal_2)(int, QString) = &MainWidget::signal_1;/* 槽的函数指针 *//* 因为信号与槽函数都可以函数重载 要用函数指针来区分 *//* slot_Print(int data, QString str) 与 slot_Print() 如果不用槽函数就不知道调用有参的还是无参的slot_Print */void (MainWidget::*funSlot_1)() = &MainWidget::slot_Print;void (MainWidget::*funSlot_2)(int, QString) = &MainWidget::slot_Print;connect(this, funSignal_1, this, funSlot_1);connect(this, funSignal_2, this, funSlot_2);
}MainWidget::~MainWidget()
{
}void MainWidget::slot_Print()
{qDebug()<< "接收到信号";
}void MainWidget::slot_Print(int data, QString str)
{qDebug()<< data << str;
}void MainWidget::slot_cf()
{emit signal_1();
}void MainWidget::slot_cf_1()
{emit signal_1(77, "mike");
}

总结:自定义带参的信号与槽。
按键1: 按下调用 slot_Print(int data, QString str) 所以最后对应槽打印的值是77 与 mike。
按键2:按下调用slot_Print()

由于信号与槽都可以函数重载(带参的与无参的信号与槽会函数名一样)在connect里会不知道调用哪一个。所以用到了函数重载。
否则会报如下错误:

error: no matching function for call to 'MainWidget::connect(MainWidget, , MainWidget*, )’
没有匹配的函数用于调用“mainwidget::connect(mainwidget*,<未解析的重载函数类型>,mainwidget*,<已解析的重载功能类型>)”*

2、QT4的方式

QT4的信号与槽是用两个宏来修饰:SIGNAL SLOT。

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QWidget>
#include <QPushButton>class MainWidget : public QWidget
{Q_OBJECTpublic:MainWidget(QWidget *parent = nullptr);~MainWidget();
signals:void signal_1(); /* 自定义一个信号 */public slots:void slot_Print(); /* 自定义槽函数 */void slot_cf();private:QPushButton *button;
};
#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include <QDebug>MainWidget::MainWidget(QWidget *parent): QWidget(parent)
{button = new QPushButton(this);button->setText("确定");button->move(100, 100);connect(button, SIGNAL(pressed()), this, SLOT(slot_cf()));connect(this, SIGNAL(signal_1()), this, SLOT(slot_Print()));
}MainWidget::~MainWidget()
{
}void MainWidget::slot_Print()
{qDebug()<< "接收到信号";
}void MainWidget::slot_cf()
{emit signal_1();
}

总结:功能跟QT5无参的信号与槽的功能一样。只是connect用QT4来实现。
QT4的注意事项:
1. 信号与槽必须有signals与slots来修饰。如果是槽还要在slots加上修饰符。
2. 如果是带参的信号与槽在SIGNAL里与SLOT里信号与槽不能包含任何的变量名。只能有类型。
3. SIGNAL与SLOT要配套使用。
4. SIGNAL与SLOT是把信号与槽直接转为字符串。如果信号与槽的名字写错。是没有编译错误的。只有在运行时报错。这无疑增加程序员的负担。

3、C++11的语法 Lambda表达式

Lambda表达式是匿名槽函数。C++11的新特性。配合QT的信号一起使用非常方便。
用法:
connect(发送者,&发送者类名::信号,
[ ] ()
{
};

在这里插入图片描述
[ 函数对象参数 ] (操作符重载函数参数) mutable或exception ->返回值{函数体}
下面重点介绍上面六部分

1、函数对象参数

在这里插入图片描述
在这里插入图片描述

2、操作符重载函数参数

()中接收信号的参数,跟信号的函数原型一致。
在这里插入图片描述

3、可修改标示符

在这里插入图片描述

4、错误抛出标示符

在这里插入图片描述

5、函数返回值

在这里插入图片描述

6、是函数体

在这里插入图片描述
Lambda的dome:

#include "mainwidget.h"
#include <QDebug>
MainWidget::MainWidget(QWidget *parent): QWidget(parent)
{button = new QPushButton(this);button->setText("确定");button->move(100, 100);/* 简单的Lambda表达式 */connect(button, &QPushButton::pressed,[=](){qDebug() << "信号";});
}

4.信号与槽的总结

信号与槽的用法有三种:建议优先用QT5的与Lambda表达式的。
信号注意点:
1、信号必须在类中声明并且加sigals关键字 没有定义也无返回值。
2、两个同名的信号可以函数重载。用函数指针来区分。
3、发送信号用emit 关键字

槽函数注意点:
1、函数名相同可以重载。用函数指针来区分。
2、函数可以是任意的成员函数,普通函数全局函数、静态函数。
3、槽函数要与信号一致。没有返回值。
在这里插入图片描述

5.信号与槽的扩展

在这里插入图片描述
第三点就是信号的扩散

6. 总结

主要介绍了QT中信号与槽的各种用法以及信号与的槽的注意事项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/314691.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32存储左右互搏 SPI总线读写FRAM MB85RS2M

STM32存储左右互搏 SPI总线读写FRAM MB85RS2M 在中低容量存储领域&#xff0c;除了FLASH的使用&#xff0c;&#xff0c;还有铁电存储器FRAM的使用&#xff0c;相对于FLASH&#xff0c;FRAM写操作时不需要预擦除&#xff0c;所以执行写操作时可以达到更高的速度&#xff0c;其…

SAP 资产管理后台配置之设定主数据字段

前阵子给财务创建了一个固定资产类型&#xff0c;但同事使用时发现字段跟平时不一样。 正常是有下面这些标签页的 然后我找到主数据屏幕格式的配置里发现 发现格式默认错了 应该是默认我司的自定义格式ZSAP 但是改成ZSAP还是不会生效 需要给这个资产分类重新分配一下字段标签页…

redis安装与配置(Ubuntu)

目录 1. 切换到 root 用户 2. 搜索安装包 3. 安装 redis 4. 查看 redis 是否正常存在 5. 修改ip 6. 重新启动服务器 7. 连接服务器 1. 切换到 root 用户 通过 su 命令切换到 root 用户。 2. 搜索安装包 apt search redis 这里安装的是下面的版本&#xff1a; 3. 安装 …

经典卷积神经网络-ResNet

经典卷积神经网络-ResNet 一、背景介绍 残差神经网络(ResNet)是由微软研究院的何恺明、张祥雨、任少卿、孙剑等人提出的。ResNet 在2015 年的ILSVRC&#xff08;ImageNet Large Scale Visual Recognition Challenge&#xff09;中取得了冠军。残差神经网络的主要贡献是发现了…

Vue中全局事件总线的配置和原理

实现任意组件之间的通信 任意组件通信的原理&#xff1a; 1、实现任意组件之间的通信,需要一个傀儡。这个傀儡既能被vm访问到,也能被VueComponent访问。 2、VueComponent.prototype.proto Vue.prototype为图上1.0黄色的线路。是Vue让组件实例对象VueComponent可以访问到Vue原…

跟着cherno手搓游戏引擎【3】事件系统和预编译头文件

不多说了直接上代码&#xff0c;课程中的架构讲的比较宽泛&#xff0c;而且有些方法写完之后并未测试。所以先把代码写完。理解其原理&#xff0c;未来使用时候会再此完善此博客。 文件架构&#xff1a; Event.h:核心基类 #pragma once #include"../Core.h" #inclu…

大二第17周总结——2023年的最后一天

本周&#xff0c;学校安排的是数据结构的程序设计&#xff0c;设计是挺好设计的&#xff0c;小半天搞完了&#xff0c;然后帮室友也搞了。内容在上一个博客。 学习上嘛~ 学了一下websocket,看了下微信小程序........ 今天早上做了一套小米的面试题&#xff0c;不做不知道&…

【数据库原理】(1)数据库技术的发展

数据与信息 数据&#xff1a;数据并非只是数字&#xff0c;像文字、符号、图像、影音等都属于数据的范畴。但一般会用数字来表述客观事物的数量、质量、关系等&#xff0c;便于更加直观的看待问题。 语义&#xff1a;数据还需要结合关联的语义解释才能够清晰的描述事物&#…

CMake入门教程【基础篇】CMake+vs2022+nmake构建项目

文章目录 1.vs编译器下载安装2.运行nmake测试3.CMake下载安装4.运行CMake测试5.使用CMakeNMake构建项目代码目录代码实现 6.运行项目 1.vs编译器下载安装 下载地址 :https://visualstudio.microsoft.com/zh-hans/vs/ 点击截图处下载 勾选红框的内容即可 安装 2.运行nmak…

【Matlab】LSTM长短期记忆神经网络时序预测算法(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88688439 一&#xff0c;概述 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种常用的循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;结构&#xff0c;由于其对于…

【解决复杂链式任务打造全能助手】大模型思维链 CoT 应用:LangChain 大模型 结合 做 AutoGPT

大模型思维链 CoT 应用&#xff1a;langchain 大模型 结合 做 AutoGPT&#xff0c;解决复杂链式任务打造全能助手 思维链 CoTLangChain基础层&#xff1a;models、LLMs、index能力层&#xff1a;Chains、Memory、Tools应用层&#xff1a;文档问答、数据库问答、智能体Agents La…

航芯ACM32G103开发板评测 03 RT-Thread Nano移植 线程管理测试

航芯ACM32G103开发板评测 07 RT-Thread Nano移植 线程管理测试 1. 软硬件平台 ACM32G103 Board开发板MDK-ARM KeilRT-Thread Nano 源码 2. 物联网RTOS—RT-Thread ​ RT-Thread诞生于2006年&#xff0c;是一款以开源、中立、社区化发展起来的物联网操作系统。 RT-Thread主…