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

Qt学习Day2:信号槽

1. 信号槽

信号槽是Qt在C++基础上新增的特性,类似于其他编程语言中回调函数的概念。信号槽使用起来非常方便,可以实现Qt对象之间的通信。

使用的前提条件有两个:

● 对象必须继承自QObject类,QObject是Qt所有对象的基类,也是QWidget的基类

● 类中要包含Q_OBJECT宏

2. 函数原型

// 连接信号槽
// 参数1:发射者,信号函数的发出者,因果关系中因的名词对象
// 参数2:信号函数,需要使用SIGNAL包裹信号函数的名称,因果关系中因的动词,第一次使用时通常需要查询
// 参数3:接收者,槽函数的执行者,因果关系中果的执行名词对象
// 参数4:槽函数,需要使用SLOT包裹槽函数的名称,因果关系中果的动词,第一次使用时通常需要查询QObject::connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)                 [static]

3. 连接

为了学习方便,逐步分为三种连接方式,非官方分类。

3.1 自带信号→自带槽

最简单的一种信号槽连接情况,因为信号函数和槽函数都是Qt内置的,程序员只需要查询后建立连接即可。

【例子】点击按钮,关闭窗口。

分析:

发射者——按钮对象,

信号函数——void QAbstractButton::clicked(bool checked = false) [signal]

接收者——窗口对象

槽函数——bool QWidget::close() [slot]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn;
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(300,300);btn = new QPushButton("关闭窗口",this);btn->move(100,100);// 连接信号槽时需要确保发射者和接收者对象均创建完成connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}Dialog::~Dialog()
{delete btn;
}

3.2 自带信号 → 自定义槽

3.1节中的连接方式并不能实现一些特殊功能的槽函数,这种情况下需要程序员手动编写槽函数,这种方式也是使用最多的一种连接方式。

槽函数是一种特殊的成员函数,因此也受权限修饰符的影响,几乎不影响信号槽的使用,但是会影响作为成员的调用。

【例子】

点击按钮,窗口向右下角移动并输出坐标。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn;// 声明槽函数
private slots: // 私有槽函数void btnClickedSlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(300,300);btn = new QPushButton("关闭窗口",this);btn->move(100,100);// 发射者:btn// 信号函数:clicked// 接收者:this// 槽函数:btnClickedSlotconnect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}// 定义槽函数
void Dialog::btnClickedSlot()
{// 获取当前的坐标int x = this->x();int y = this->y();x += 10;y += 10;// 移动窗口move(x,y);qDebug() << x << y;
}Dialog::~Dialog()
{delete btn;
}

3.3 自定义信号 → 槽

本节内容属于强行教学,因为自定义信号主要在后期解决特殊情况下的问题。

信号函数是一种特殊的函数,只有声明,没有定义,且不能调用只能配合emit关键字发送,也没有权限。

【例子】点击按钮,关闭窗口。

在3.1节中使用一个信号槽解决此问题,也是问题的最优解;本节使用两个信号槽连接解决此问题,在第一个连接的槽函数中发射一个自定义信号,使用这个自定义信号再触发关闭窗口的功能。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn;private slots:void btnClickedSlot();// 声明信号函数
signals:void mySignal(); // 自定义信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(300,300);btn = new QPushButton("关闭窗口",this);btn->move(100,100);// 点击按钮 → 自定义槽函数connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));// 使用自定义信号触发关闭窗口的效果connect(this,SIGNAL(mySignal()),this,SLOT(close()));}void Dialog::btnClickedSlot()
{// 发射自定义信号emit mySignal();
}Dialog::~Dialog()
{delete btn;
}

4.传参

【例子】点击按钮,按钮上显示点击的次数。

正常的解法是使用成员变量计数。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn;int count; // 点击次数private slots:void btnClickedSlot(); // 点击按钮的槽函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent),count(0) // 构造初始化列表
{resize(300,300);btn = new QPushButton("0",this);btn->move(100,50);connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}void Dialog::btnClickedSlot()
{// 次数+1count++;// int → QStringQString text = QString::number(count);// 设置按钮当前点击的次数btn->setText(text);
}Dialog::~Dialog()
{delete btn;
}

为了演示信号槽传参,强行使用信号槽进行参数传递。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn;int count; // 点击次数private slots:void btnClickedSlot(); // 点击按钮的槽函数void countSlot(int); // 此槽函数表示可以接收一个int参数signals:// 此信号函数可以携带一个int参数发射void countSignal(int);
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent),count(0) // 构造初始化列表
{resize(300,300);btn = new QPushButton("0",this);btn->move(100,50);connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));connect(this,SIGNAL(countSignal(int)),this,SLOT(countSlot(int)));
}void Dialog::btnClickedSlot()
{// 次数+1count++;// 发射一个自定义信号,携带count参数emit countSignal(count);
}// 接收参数的槽函数
void Dialog::countSlot(int count)
{qDebug() << &this->count << &count;// int → QStringQString text = QString::number(count);btn->setText(text);
}Dialog::~Dialog()
{delete btn;
}

信号与槽参数关系:

1. 理论上可以传递任意个数的参数

2. 信号的参数个数必须大于等于槽的参数个数

3. 参数类型必须一一匹配

5.对应关系

一对多:同一个信号可以连接到多个槽函数。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn;QPushButton* btn2;private slots:void customSlot1();void customSlot2();void customSlot3();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(300,300);btn = new QPushButton("一对多",this);btn2 = new QPushButton("一对多",this);btn->move(100,100);btn2->move(100,150);// 一个信号连接多个槽函数connect(btn,SIGNAL(clicked()),this,SLOT(customSlot1()));connect(btn,SIGNAL(clicked()),this,SLOT(customSlot2()));// 断开连接
//    disconnect(btn,SIGNAL(clicked()),
//            this,SLOT(customSlot2()));// 一个信号连接一个槽connect(btn2,SIGNAL(clicked()),this,SLOT(customSlot3()));
}void Dialog::customSlot1()
{qDebug() << "A";
}void Dialog::customSlot2()
{qDebug() << "B";
}void Dialog::customSlot3()
{// 当做是普通的成员函数直接调用customSlot1();customSlot2();
}Dialog::~Dialog()
{delete btn;
}

多对一:多个信号可以同时连接一个槽函数。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = 0);~Dialog();private:QPushButton* btn1;QPushButton* btn2;private slots:void btnsClickedSlot(); // 槽函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent)
{resize(300,300);btn1 = new QPushButton("A",this);btn2 = new QPushButton("B",this);btn1->move(100,100);btn2->move(100,150);connect(btn1,SIGNAL(clicked()),this,SLOT(btnsClickedSlot()));connect(btn2,SIGNAL(clicked()),this,SLOT(btnsClickedSlot()));
}void Dialog::btnsClickedSlot()
{// 可以使用sender函数获取发射者对象if(btn1 == sender()){qDebug() << "疯狂星期四1";}else if(btn2 == sender()){qDebug() << "疯狂星期四2";}
}Dialog::~Dialog()
{delete btn1;delete btn2;
}
http://www.xdnf.cn/news/331111.html

相关文章:

  • 从SQL的执行流程彻底详解预编译是如何解决SQL注入问题
  • Linux57配置MYSQL YUM源
  • 离散化(竞赛)
  • MinIo安装和使用操作说明(windows)
  • C++相关学习过程
  • 《USB技术应用与开发》第七讲:CDC串口设备案例
  • 【AlphaFold2】深入浅出,讲解Evoformer|学习笔记
  • 【汇正自控阀门集团】签约智橙PLM,智橙助泵阀“以国代进”
  • ntdll!CsrServerApiRoutine函数--csrsrv!CsrCallServerFromServer什么时候被调用?
  • 计算机硬件(南桥):主板芯片组FCH和PCH的区别
  • 苍穹外卖(用户下单、订单支付)
  • 当体育数据API遇上WebSocket:一场技术互补的「攻防战」
  • UGUI如何使用EventTrigger
  • LeetCode105_从先序与中序遍历序列构造二叉树
  • 如何从路由表优化的角度理解[CIDR]无类别域间路由选择技术?
  • 六级阅读---2024.12 卷一 仔细阅读1
  • 【编译原理】第五章 自下而上语法分析
  • 快速上手SpringBoot开发指南
  • 力扣热题100之反转链表
  • Linux系统Shell脚本之shell数组、正则表达式、及AWK
  • Mongo3.4升级到mongo6性能降低9倍
  • HSV颜色空间
  • 51camera将参加第九届沥青路面论坛暨新技术新成果展示会
  • 代码随想录算法训练营第三十三天(补)
  • Unity Gizmos
  • 题解 洛谷 Luogu P1073 [NOIP 2009 提高组] 最优贸易 强连通分量 Tarjan 缩点 拓扑排序 动态规划 C++
  • Vue与Python的深度整合:构建现代Web应用的全栈范式
  • 国标GB28181设备管理软件EasyGBS打造明厨亮灶食品安全监管防线
  • 对称二叉树(简单)
  • sqlite数据库操作