什么是信号与槽??
在GUI编程中,通常我们更改一个部件时,都希望通知另一个部件。例如,如果用户单击“关闭”按钮,可能希望调用窗口的close()函数。 在Qt中,就通过信号与槽的机制来实现这种需求,当发生特定事件时会发出信号,而槽就是是响应特定信号而调用的函数。
信号和插槽用于对象之间的通信。信号与槽机制是Qt的主要功能也是与其他框架提供的功能最大不同的部分。 部分框架使用回调函数来实现对象间的通信,与回调相比,信号和插槽由于提供了更大的灵活性而稍慢一些, 尽管实际应用中的差异并不明显。通常,发出连接到某些插槽的信号的速度比使用非虚拟函数调用直接调用接收器的速度大约慢十倍。 这是定位连接对象,安全地迭代所有连接(即,检查后续接收方在发射期间是否未被销毁)以及以通用方式编组任何参数所需的开销。
所谓信号就是一个公共访问函数,当对象的内部状态以某种可能使对象的客户端或所有者感兴趣的方式更改时,该对象就会发出信号。发出信号时,通常会立即执行与其连接的插槽,就像正常的函数调用一样。发生这种情况时,信号和时隙机制完全独立于任何GUI事件循环。 emit一旦所有插槽都返回,将执行该语句之后的代码。使用排队连接时情况略有不同; 在这种情况下,emit关键字后面的代码将立即继续,并且稍后将执行插槽。 如果将多个插槽连接到一个信号,则在发出信号时,将按照连接的顺序依次执行插槽。** 信号是由Moc自动生成的,不能在.cpp文件中实现,永远不能有返回类型(即use void)。 所谓槽也是一个正常的C++函数,可以正常调用。它们唯一的不同就是可以将信号连接到它们。**
一个对象发送一个信号出去,另外一个对象接收到该信号后,会触发相应的槽函数。 前提:信号要和槽函数进行绑定
C 语言的信号
信号的注册:
NAME
signal - ANSI C signal handling
SYNOPSIS
#include <signal.h>
typedef void (*sighandler_t)(int); //int 触发该函数的信号值
sighandler_t signal(int signum, sighandler_t handler);
signum :需要注册的信号
handler :信号处理函数
--------------------
信号发送:
NAME
kill - send signal to a process
SYNOPSIS
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
C 语言中的信号可以让用户自定义的吗???
不能的,只能使用系统已经预定义好的一些信号
────────────────────────────────────────────────────────────
SIGABRT P1990 Core Abort signal from abort(3)
SIGALRM P1990 Term Timer signal from alarm(2)
SIGBUS P2001 Core Bus error (bad memory access)
SIGCHLD P1990 Ign Child stopped or terminated
SIGCLD - Ign A synonym for SIGCHLD
SIGCONT P1990 Cont Continue if stopped
SIGEMT - Term Emulator trap
SIGFPE P1990 Core Floating-point exception
SIGHUP P1990 Term Hangup detected on controlling terminal
or death of controlling process
SIGILL P1990 Core Illegal Instruction
SIGINFO - A synonym for SIGPWR
SIGINT P1990 Term Interrupt from keyboard
--------------------------
C 语言的信号可以传递大量的数据吗????
不可以的。
所以QT 在C 的基础上对信号进行优化。 来实现QT 中的信号与槽,方便对象 与 对象之间的数据交互。
系统中的信号与槽
在QT中,主流控件是已经定义好了很多信号的,并且大部分信号都是已经连接了槽函数。但是这个槽函数要么就是接口,要么就是空实现。 我们要实现或者重新完成自己逻辑。
比如:QPushButton
写槽函数就OK
void MainWindow::on_login_btn_clicked()
{
}
QT 中的信号与槽的连接语法
connect(信号的发送者,SIGNAL(信号名称),信号的接收者,SLOT(槽函数));
//QT 4 的写法
connect(sender, SIGNAL(valueChanged(QString, QString)),receiver,
SLOT(updateValue(QString)));
//QT 5的写法
connect(信号的发送者,&信号所在的类名::信号名称,信号的接收者,&接收者的类名::槽函数);
connect(sender, &Sender::valueChanged,eceiver, &Receiver::updateValue);
信号与槽的定义
1.在需要接收信号的类中 声明槽函数
//声明槽函数
public slots:
void set_label();
2.在xxx.cpp 中实现槽函数
void MainWindow::set_label()
{
ui->label->setText("设置标签成功!!!666");
}
3.进行信号与槽的关联
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(set_label()));
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//信号还是用pushbutton定义函数信号 clicked() 连接自己槽函数
// 发送者:ui->pushButton
// 信号名称:clicked(),不是我们自定义,也就是不用我们发信号
//接收者: this表示当前窗体
// 槽函数: setLabelValue
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(setLabelValue()));
}
void MainWindow::setLabelValue(){
ui->label->setText("nB。。。。。");
}
MainWindow::~MainWindow()
{
delete ui;
}
用户自定义信号
1.去到信号的发送者类中声明信号
signals:
void mysig();
2.关联信号与槽
connect(this,SIGNAL(mysig()),this,SLOT(set_label()));
3.发送信号
emit mysig();
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals: //定义信号
void mySig();
public slots:
void setVal();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//连接槽函数 this作为发送者
// QT4 可读性好,不太好写
//connect(this,SIGNAL(mySig()),this,SLOT(setVal()));
//QT5 这个好。。。写起来简单。但是可读性查
connect(this,&MainWindow::mySig,this,&MainWindow::setVal);
//发送信号
emit mySig();
}
void MainWindow::setVal(){
ui->label->setText("这是设置的心智。。。。。。");
}
MainWindow::~MainWindow()
{
delete ui;
}
信号与槽的参数传递
1.定义一个带参的信号
signals:
//定义一个带参的信号
void mysig(int a);
2.定义一个带参数的槽
public slots:
void get_sig(int a);
3.进行信号与槽的关联
connect(this,SIGNAL(mysig(QString )),this,SLOT(get_sig(QString )));
或者QT5 写法
connect(this,&MainWindow::mysig,this,&MainWindow::get_sig);
4.发送带参数的信号
emit mysig("HELLO QT");
信号参数转递的注意事项:
1.信号与槽的参数类型必须要匹配
2.发送者的参数的个数 必须要大于或等于 接收者参数的个数
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals: //定义信号
void mySig(QString a,int b,int c);
public slots:
void setVal(QString a,int b);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//连接槽函数 this作为发送者
// QT4 可读性好,不太好写
connect(this,SIGNAL(mySig(QString,int,int)),this,SLOT(setVal(QString,int)));
//QT5 这个好。。。写起来简单。但是可读性查
//connect(this,&MainWindow::mySig,this,&MainWindow::setVal);
//发送信号
emit mySig("睡觉!",1,2);
//扩展:
//方案1:如果参数过多可以通用结构体或者类封装然后通过接头体实例或者对象接收。--自己的系统
//方案2: 跨应用
//xml <person><name>zs</name><age>18<age/></person>
//Json {}对象 [{},{}]数组 使用json库转换得到json字符串,对方用json库转换得到多个参数就OK
}
void MainWindow::setVal(QString a,int b){
qDebug()<< "接收到信号传递过来的参数:" <<a << b<<endl;
ui->label->setText("这是设置的心智。。。。。。");
}
MainWindow::~MainWindow()
{
delete ui;
}
信号与槽的相互关联
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void mySig01();
void mySig02();
public slots:
void getMySig01();
void getMySig02();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//连接 一个信号对应两个操作
// connect(this,SIGNAL(mySig01()),this,SLOT(getMySig01()));
// connect(this,SIGNAL(mySig01()),this,SLOT(getMySig02()));
//发信号 两个信号???? 两个按钮
connect(this,SIGNAL(mySig01()),this,SLOT(getMySig01()));
connect(this,SIGNAL(mySig02()),this,SLOT(getMySig01()));
}
MainWindow::~MainWindow()
{
delete ui;
}
int index =0;
void MainWindow::getMySig01()
{
qDebug()<<"getMySig01 " << index++ << "....."<<endl;
}
void MainWindow::getMySig02()
{
qDebug()<<"getMySig02....."<<endl;
}
void MainWindow::on_pushButton_clicked()
{
//发送信号1
qDebug() << "已经发送信号1" <<endl;
emit mySig01();
}
void MainWindow::on_pushButton_2_clicked()
{
//发送信号2
qDebug() << "已经发送信号2" <<endl;
emit mySig02();
}
信号与槽的取消关联
语法:
disconnect(信号的发送者,SIGNAL(发送的信号),信号的接收者,SLOT(接收的信号));
例子:
disconnect(this,SIGNAL(mysig()),this,SLOT(get_sig()));
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
int index=0;
void MainWindow::on_pushButton_clicked()
{
//QString str = "内容为:%1";
//链式编程
//QString result = str.arg(index++);
QString result = "内容为:" + QString::number(index++);
ui->label->setText(result);
}
void MainWindow::on_pushButton_2_clicked()
{
//取消关联
disconnect(ui->pushButton,
SIGNAL(clicked()),
this,
SLOT(on_pushButton_clicked()));
}
void MainWindow::on_pushButton_3_clicked()
{
//再次关联
connect(ui->pushButton,
SIGNAL(clicked()),
this,
SLOT(on_pushButton_clicked()));
}