QT 的信号与槽

什么是信号与槽??

在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()));
}

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值