Qt学习笔记(二):信号和槽
标签: Qt学习笔记
一、创建一个基于 QWidget 的项目,不带有界面设计器:

二、在主窗口下添加两个按钮对象,连接按钮发出的信号和槽函数:
mywidget.h:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
// 引入按钮头文件
#include <QPushButton>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
~MyWidget();
private:
// 声明两个按钮对象
QPushButton b1; // 普通对象
QPushButton *b2; // 指针对象
};
#endif // MYWIDGET_H
mywidget.cpp:
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
// 通过 setParent 方法指定父对象
b1.setParent(this);
b1.setText("Button1");
b1.resize(80, 40);
b1.move(200, 100);
// 通过构造函数方法指定父对象
b2 = new QPushButton(this);
b2->setText("Button2");
b2->resize(80, 40);
b2->move(30, 20);
/*
* 连接信号和槽:点击按钮的时候,关闭当前窗口
* 参数1:信号的发送者(指针类型)
* 参数2:发送的信号;&发送者的名字::信号名称
* 参数3:信号的接收者(指针类型)
* 参数4:处理信号的函数(叫做槽函数);&接收者的名字::槽函数名称
*/
connect(&b1, &QPushButton::clicked, this, &MyWidget::close);
// 连接信号和槽:按下按钮的时候,当前窗口最大化显示
connect(b2, &QPushButton::pressed, this, &MyWidget::showMaximized);
// 重置主窗口的大小
this->resize(600, 400);
}
MyWidget::~MyWidget()
{
}
其中信号 &QPushButton::clicked、&QPushButton::pressed,
和槽函数 &MyWidget::close、&MyWidget::showMaximized 都是 Qt 定义好的;
可以在 Qt 帮助文档里查找:


三、我们也可以自定义槽函数:
自定义槽函数的特点:槽函数的本质就是一个普通函数,在 Qt5 里面,自定义槽函数可以是成员函数、普通全局函数、或者静态函数都行;槽函数的返回值和参数需要和信号一致;
注意:信号和槽函数都没有返回值,但是可以带参数;
在 mywidget.h 中声明一个自定义的槽函数:

在 mywidget.cpp 中连接信号和自定义槽函数:
注意:一个信号可以连接多个槽函数;

四、自定义信号:
案例:添加一个子窗口,在主窗口上点击按钮的时候,主窗口隐藏,子窗口显示;
点击子窗口上的按钮的时候,子窗口隐藏,主窗口显示;
1、在 Qt 项目上添加子窗口:



2、在子窗口头文件中添加自定义信号:
childwidget.h 文件为:
#ifndef CHILDWIDGET_H
#define CHILDWIDGET_H
#include <QWidget>
#include <QPushButton>
class ChildWidget : public QWidget
{
Q_OBJECT
public:
explicit ChildWidget(QWidget *parent = 0);
signals:
// 自定义信号必须由 signals 关键字声明;
// 自定义信号没有返回值,但可以有参数;
// 自定义信号就是函数的声明,只需声明,无需定义;
// 发送信息使用关键字 emit;
void mySignal();
public slots:
// Qt5 里面自定义槽函数不是必须由 public slots 声明;
// 但是 Qt4 里面槽函数必须由 public slots 声明;
void sendSignal();
private:
// 创建一个按钮对象
QPushButton btn;
};
#endif // CHILDWIDGET_H
3、在子窗口中点击按钮时,发送自定义信号:
childwidget.cpp 文件为:
#include "childwidget.h"
ChildWidget::ChildWidget(QWidget *parent) :
QWidget(parent)
{
this->resize(400, 300); // 设置窗口大小
this->setWindowTitle("子窗口"); // 设置窗口标题
btn.setParent(this);
btn.setText("切换到主窗口");
btn.move(200, 100);
// 点击按钮,调用自定义槽函数(sendSignal),发送自定义信号(mySignal)
connect(&btn, &QPushButton::clicked, this, &ChildWidget::sendSignal);
}
// 自定义槽函数
void ChildWidget::sendSignal()
{
// 发送自定义信号
emit mySignal();
}
4、在主窗口中添加子窗口对象,并自定义槽函数处理子窗口发出的信号:
修改 mywidget.h 文件为:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QPushButton>
// 在主窗口中引入子窗口的头文件
#include "childwidget.h"
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
~MyWidget();
// 自定义槽函数
void mySlot();
// 处理自定义信号的槽函数
void dealSignal();
private:
QPushButton b1;
// 在主窗口中声明子窗口对象
ChildWidget child;
};
#endif // MYWIDGET_H
5、点击主窗口上的按钮,隐藏主窗口,并显示子窗口;
同时连接子窗口发出的信号和槽函数,当接收到信号时,显示主窗口,隐藏子窗口:
修改 mywidget.cpp 文件为:
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
this->resize(400, 300); // 设置窗口大小
this->setWindowTitle("主窗口"); // 设置窗口标题
b1.setParent(this);
b1.setText("切换到子窗口");
b1.move(200, 100);
// 点击按钮,调用自定义槽函数(mySlot),隐藏主窗口,显示子窗口
connect(&b1, &QPushButton::clicked, this, &MyWidget::mySlot);
// 连接子窗口的自定义信号和主窗口中的自定义槽函数
// 参数1:信号的发送者(子窗口)
// 参数2:发送的信号(子窗口自定义的信号)
// 参数3:信号的接收者(主窗口)
// 参数4:处理信号的自定义槽函数
connect(&child, &ChildWidget::mySignal, this, &MyWidget::dealSignal);
}
// 自定义槽函数
void MyWidget::mySlot()
{
// 隐藏主窗口
this->hide();
// 显示子窗口
child.show();
}
// 处理信号的自定义槽函数
void MyWidget::dealSignal()
{
// 显示主窗口
this->show();
// 隐藏子窗口
child.hide();
}
MyWidget::~MyWidget()
{
}
五、带参数的自定义信号和自定义槽函数:
在上面案例的子窗口头文件(childwidget.h)中自定义一个带参信号:

并在子窗口上点击按钮的时候,发送带参信号:

在主窗口头文件(mywidget.h)中自定义一个相对应的带参槽函数:

在主窗口中处理无参和有参的信号:
// 因为信号和槽函数都重载了,所以直接使用 connect 连接信号和槽的时候会报错,
// 因为存在二义性,不确定调用的是无参的,还是有参的;
// 可以使用函数指针来解决:
// 无参数的信号和槽函数的函数指针:
void(ChildWidget::*noParamSignal)(void) = &ChildWidget::mySignal;
void(MyWidget::*noParamSlot)(void) = &MyWidget::dealSignal;
// 有参数的信号和槽函数的函数指针:
void(ChildWidget::*haveParamSignal)(int, QString) = &ChildWidget::mySignal;
void(MyWidget::*haveParamSlot)(int, QString) = &MyWidget::dealSignal;
// 连接无参数的自定义信号和无参数的槽函数
// 函数指针 noParamSignal 就表示无参的信号,
// 函数指针 noParamSlot 就表示无参的槽函数;
connect(&child, noParamSignal, this, noParamSlot);
// 连接带参数的自定义信号和带参数的槽函数
connect(&child, haveParamSignal, this, haveParamSlot);
测试结果如下:

老师的视频在演示的时候,qDebug() 输出 QString 数据是中文时会出现乱码,如下:

但我的可以直接输出中文;如果中文输出乱码,可以将 QString 类型转换成 char* 类型:

六、上面使用 函数指针 的方式区别无参和有参信号的方法是 Qt5 之后才有的,在 Qt4 的时候是另一种方法区分无参和有参的信号,如下:
// 连接无参的信号和无参的槽函数
connect(&child, SIGNAL(mySignal()), this, SLOT(dealSignal()));
// 连接有参的信号和有参的槽函数
connect(&child, SIGNAL(mySignal(int,QString)), this, SLOT(dealSignal(int,QString)));
Qt4 的这种方式用起来比较方便,但是有一个缺点:SIGNAL 和 SLOT 宏会将信号名称和槽函数名称转换成字符串,在项目编译的时候不进行错误检查;也就是说信号名称和槽函数名称写错了,也可以编译通过,但是程序会在运行的时候直接崩掉。
智能推荐
【Qt学习笔记】1:认识和使用Qt,信号槽,创建Qt的GUI程序
Qt5的安装很方便,在官网下载后直接安装即可,也不去使用VS,而是用自带的Qt Creater开发环境。 安装时只需要选择版本下的一个MinGW工具即可,而Qt Creater则会在Tool下自动勾选。 风格定制 使用黑色主题 使用真实制表符严格对齐 Qt默认的Tab是四个空格,改一下。 Ctrl+A全选后Ctrl+I可以自动对齐代码。 Qt的HelloWorld 它也和普通的C++程序一样从主函...
linux上安装Qt4.8.6+QtCreator4.0.3
一、Qt简介 Qt是1991年奇趣科技开发的一个跨平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能。Qt很容易扩展,并且允许真正地组件编程。 准备工作 操作系统:centos6.5 位数:64位 二、安装 1、获取源码Qt4.8.6 2、获取源码QtCreator4.0.3 2、安装QtCreator4.0.3 进入QtCreator安装界面,指定...
react-native metro 分析
文章目录 前言 概念 Resolution Transformation Serialization 打包方式 Moudles Plain bundle Indexed RAM bundle File RAM bundle 流程 前置流程 resolve流程 Transformer流程 序列化流程 缓存 为什么要缓存 缓存的请求与缓存 Metro配置 结构 前言 metro是一种支持ReactNa...
嵌入式Linux——应用调试:用户态打印段错误信息
简介: 很多时候我们会遇到段错误:segmentation fault,而段错误有时是由内核引起的,有时是由应用程序引起的。在内核态时,发生段错误时会打印oops信息,但是在用户态时,发生段错误却只会打印segmentation fault而并不会打印其他的信息。所以本文主要介绍在用户态时,通过修改内核设置和添加启动参数来打印引发segmentati...
springboot1.4.1整合logback 遇到的问题
springboot1.4.1整合logback 遇到的问题 项目使用了springboot1.4.1整合logback,然而设置的过期时间15 并没有生效, 2GB达到2G自动删除也没有生效,仅仅实现了按大小分割。 经过查看pom 父工程内的源码发现是默认的logback版本是1.1.7,而过期时间配置是在logback 1.1.8以后才支持的。 不得不说这是springboot1.4.1 的b...
猜你喜欢
记一次C/S架构的渗透测试
概述 目标站点是http://www.example.com,官网提供了api使用文档,但是对其测试后没有发现漏洞,目录、端口扫描等都未发现可利用的点。后发现官网提供了客户端下载,遂对其进行一番测试。 信息收集 先抓了下客户端的包,使用Fiddler和BurpSuite都抓不到,怀疑走的不是HTTP协议,用WireShark查看其确实用的是HTTP协议,但是数据包不好重放,这里最后使用了WSExp...
Linux:结合Securecrt进行文件上传(lrzsz)P2
1、安装rzsz软件 2、点击Scurecrt的option——X/Y/Z配置上传和下载目录 3、首先在Linux里切换到一个目录,然后用rz命令,文件就会上传到钙Linux的目录下 只要敲rz即可,然后在弹出的对话框里选择需要上传的文件即可 4、下载文件用sz 下载单个文件:在当前目录下有该文件 sz filename 下载...
SQL 提示作为 布局 生存工具指南
下面是一些展示AdventureWorks中表现最好的销售人员并列出他们的经理的结构化查询语言代码。 它产生以下结果。 所以,代码是有效的,但它是丑陋的。 如果我需要理解和改进代码,我首先需要把它变成可读的形式。 我有结构化查询语言提示,所以我可以按下计算机的ctrl按键键 踢你自己),它会应用默认的内置代码样式,并对此进行修复。 不,不是,因为我相信你仍然不喜欢它的格式。 没有两个开发人员能够就...
Vue+Springboot解决数据传输时参数格式不匹配问题
前端:使用的是ant design vue ,端口号为8000 后端:使用的是springboot框架开发,端口号为8080 需求:已经解决跨域问题,前端发送登录的信息给后台,后台接收不到 样例: 前端: 后台: 请求的数据格式为json格式,后台参数类型不匹配 解决方案 第一种: 修改后端,参数类型: 第二种方式: 在前端vue框架中加入qs插件,qs 是一个增加了一些安全性的查询字符串解析和序...
Flex布局做出自适应页面--语法和案例
本文发布在: github项目地址:https://github.com/tenadolanter/flex-layout-demo SegmentFault地址:https://segmentfault.com/a/1190000012916949/ CSDN地址:http://blog.csdn.net/qq_34648000/article/details/79115294 博客园地址:ht...
