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.mzph.cn/news/590887.shtml

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

相关文章

LAYABOX:2024新年寄语

2024新年寄语 过去的一年&#xff0c;尽管许多行业面临严峻挑战和发展压力&#xff0c;小游戏领域却逆势上扬&#xff0c;年产值首次突破400亿元大关&#xff0c;众多优质小游戏企业收获颇丰。 对此&#xff0c;祝福大家&#xff0c;2024一定更好&#xff01; 过去的一年&#…

伺服电机的控制模式

一、伺服电机基本的控制模式 伺服电机的基本控制模式有位置模式、速度模式、转矩模式 二、位置模式 位置模式对速度和位置都有严格的控制&#xff0c;通过控制发送脉冲的频率&#xff0c;来确定电机的转动杆速度大小&#xff0c;通过控制发送脉冲的个数来确定转动的角度。位置…

CMake入门教程【基础篇】CMake编译平台

文章目录 简介Visual Studio支持示例 其他编译器和生成器支持MinGW示例 IDE集成Eclipse示例 实验性和特殊平台支持总结 简介 CMake是一个非常强大的跨平台自动化构建工具&#xff0c;它支持生成多种类型的项目文件&#xff0c;覆盖了广泛的开发环境和编译器。在这篇博客中&…

33--反射

1、反射(Reflection)的概念 1.1 反射的出现背景 Java程序中&#xff0c;所有的对象都有两种类型&#xff1a;编译时类型和运行时类型&#xff0c;而很多时候对象的编译时类型和运行时类型不一致。 Object obj new String("hello"); obj.getClass(); 例如&#xf…

【话题】ChatGPT等大语言模型为什么没有智能2

我们接着上一次的讨论&#xff0c;继续探索大模型的存在的问题。正巧CSDN最近在搞文章活动&#xff0c;我们来看看大模型“幻觉”。当然&#xff0c;本文可能有很多我自己的“幻觉”&#xff0c;欢迎批评指正。如果这么说的话&#xff0c;其实很容易得出一个小结论——大模型如…

DS1302N的时钟逻辑

时钟也是一个实时的串口&#xff0c;也是很简单的&#xff0c;不过要注意以下的要点&#xff1a; 要点&#xff1a; &#xff08;1&#xff09;里面有很多数据&#xff0c;所以需要定义一个结构体变量&#xff0c;将其中的数据写进去。 &#xff08;2&#xff09;写进去的数…

.Net Core 防御XSS攻击

网络安全攻击方式有很多种&#xff0c;其中包括XSS攻击、SQL注入攻击、URL篡改等。那么XSS攻击到底是什么?XSS攻击有哪几种类型? XSS攻击又称为跨站脚本&#xff0c;XSS的重点不在于跨站点&#xff0c;而是在于脚本的执行。XSS是一种经常出现在Web应用程序中的计算机安全漏洞…

算法基础之计数问题

计数问题 核心思想&#xff1a; 数位dp / 累加 累加 ​ 分情况讨论 &#xff1a; xxx 000 ~ abc –1 yyy 000 ~ 999 共 abc * 1000 种 特别地&#xff0c;当枚举数字0时 (找第4位为0的数) 前三位不能从000开始了 否则没这个数不合法(有前导零) xxx abc 2.1. d < 1 , 不…

UnityShader(四)一个最简单的顶点/片元着色器

目录 顶点/片元着色器的基本结构&#xff1a; 简单的例子 增加模型数据 顶点着色器和片元着色器之间的通信 顶点/片元着色器的基本结构&#xff1a; Shader "MyShaderName"{Properties{//属性}SubShader{//针对显卡A的SubShaderPass{//设置渲染状态和标签//开始C…

C++正则表达式全攻略:从基础到高级应用

C正则表达式全攻略&#xff1a;从基础到高级应用 一、基础知识二、正则表达式的基本匹配三、C中使用正则表达式四、高级正则表达式五、实践示例六、性能优化6.1、编译正则表达式6.2、避免过度使用回溯6.3、优化匹配算法 七、总结 一、基础知识 正则表达式是一种用于匹配、搜索…

voronoi diagram

voronoi diagram Generalized voronoi diagram GVD Boris Lau - dynamicvoronoi 重要三篇论文链接 dynamic voronoi ros github dynamic voronoi 论文解读 - silver bullet - 慢悠悠的小马车 Voronoi-Based-Hybrid-Astar &#xff08;重要&#xff09; 重要论文 Local a…

ORACLE Primavera P6, Unifier v23.12 系统分享

引言 根据上周的计划&#xff0c;我近日简单制作了一个基于ORACLE Primavera P6 EPPM 以及Unifier 最新版23.12的虚拟机演示环境&#xff0c;里面包括了p6 和 unifier的全套系统服务 此虚拟系统环境仅用于演示、培训和测试目的。如要在生产环境中使用此虚拟机&#xff0c;请您…

设计模式在Java开发中的应用

设计模式在Java开发中起着至关重要的作用。它们是一些被广泛接受的、经过验证有效的解决问题的方法。设计模式可以帮助开发人员构建可维护、可扩展和易于理解的代码。在本文中&#xff0c;我将介绍一些在Java开发中常用的设计模式&#xff0c;并解释它们的应用场景和优点。 单例…

系列二、RestTemplate简介

一、RestTemplate简介 1.1、概述 RestTemplate是一种便捷的访问RestFul服务的模板类&#xff0c;是Spring提供的用于访问Rest服务的客户端模板工具集&#xff0c;它提供了多种便捷访问远程HTTP服务的方法。 1.2、API https://docs.spring.io/spring-framework/docs/5.2.2.REL…

mysqldump导出函数、存储过程和视图

mysqldump导出函数、存储过程和视图 导出函数和存储过程导出视图定义 导出函数和存储过程 查看函数和存储过程&#xff1a; select routine_schema,routine_name,routine_type from information_schema.routines where routine_schemaDBNAME and routine_type in (FUNCTIO…

从马尔可夫奖励过程到马尔可夫决策到强化学习【02/2】

一、说明 随着 Open AI 于 2023 年 11 月 6 日发布GPT 代理&#xff0c;我们所有人都对它带来的支持和灵活性着迷。想象一下&#xff0c;有一个个性化的数字助手始终在您身边&#xff0c;根据您的喜好完成日常平凡任务或艰巨任务。但为这些定制代理提供动力的是强化学习&#x…

【C语言】Windows上用GTK写GUI程序

要使用GTK开发一个Windows图形用户界面程序&#xff0c;需要首先设置GTK开发环境。这通常包括安装GTK库和它的依赖&#xff0c;以及配置编译器和工具链。可以选择使用纯C语言和GTK库或者使用支持GTK绑定的其他语言&#xff0c;如Python、C或Rust。 1. 安装GTK开发库 在Window…

Linux apt 命令

apt&#xff08;Advanced Packaging Tool&#xff09;是一个在 Debian 和 Ubuntu 中的 Shell 前端软件包管理器。 apt 命令提供了查找、安装、升级、删除某一个、一组甚至全部软件包的命令&#xff0c;而且命令简洁而又好记。 apt 命令执行需要超级管理员权限(root)。 apt 语…

Prototype原型模式(创建对象)

原型模式&#xff1a;Prototype 链接&#xff1a;原型模式实例代码 注解 模式定义 使用原型实例指定创建对象的种类&#xff0c;然后通过拷贝这些原型来创建新的对象。 ——《设计模式》GoF 目的 在软件系统中&#xff0c;经常面临这“某些结构复杂的对象”的创建工作&am…

Java ArrayList解密

数组的大小是固定的&#xff0c;一旦创建的时候指定了大小&#xff0c;就不能再调整了。也就是说&#xff0c;如果数组满了&#xff0c;就不能再添加任何元素了。 ArrayList 在数组的基础上实现了自动扩容&#xff0c;并且提供了比数组更丰富的预定义方法&#xff08;各种增删改…