QT入门(二)信号与槽机制

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

4.1 系统自带的信号与槽

下面我们完成一个小功能,上面我们已经学习了按钮的创建,但是还没有体现出按钮的功能,按钮最大的功能也就是点击后触发一些事情,比如我们点击按钮,就把当前的窗口给关闭掉,那么在Qt中,这样的功能如何实现呢?
其实无法两行代码就可以搞定了,我们看下面的代码

 QPushButton * quitBtn = new QPushButton("关闭窗口",this);
  connect(quitBtn,&QPushButton::clicked,this,&MyWidget::close);

connect()函数最常用的一般形式:
connect(sender, signal, receiver, slot);
参数解释:

  •  sender:发出信号的对象
  •  signal:发送对象发出的信号
  •  receiver:接收信号的对象
  •  slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

那么系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个
请添加图片描述

小例子:按下按钮改变另一个按钮上的数字

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QDebug>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
    void change_number();
    QPushButton btn,b1,b2;
    int count=0;
};

#endif // WIDGET_H

widget.cpp:

#include "widget.h"

Widget::Widget(QWidget *parent)   //构造函数
    : QWidget(parent)
{
    btn.setParent(this);   //如果要是btn依附与窗口,则需要给它指定父类
    btn.setText("exit");    //设置文字
    btn.move(200,200);     //设置位置
    btn.setWindowTitle("project_1"); //设置应用程序标题

    //connect(b1,发出的信号,this,处理信号的槽函数)
    //b1,信号的发出者,此参数为指针
    //&QPushButton::clicked,&+信号发出类的名字+::+信号的名字
    //this,信号接收者,此参数是一个指针
    //&Widget::close,信号的处理函数,属于this
    connect(&btn,&QPushButton::clicked,this,&Widget::close);

    b1.setParent(this);
    b2.setParent(this);
    b1.setText("change_num");
    b2.setText("0");
    b1.move(100,50);
    b2.move(100,100);

    //按下b1,改变b2的数字,b2的数字在0,1二者切换
    connect(&b1,&QPushButton::clicked,this,&Widget::change_number);

}

Widget::~Widget()  //析构函数
{
    qDebug()<<"析构完成";  //需要包含头文件QDebug
}

void Widget::change_number()
{
    if(count==0)
    {
        count=1;
        b2.setText("1");
    }
    else
    {
        count=0;
        b2.setText("0");
    }

}

4.2自定义信号和槽

并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽。
下面我们看看使用 Qt 的信号槽:
自定义信号槽需要注意的事项:

  •  发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
  •  信号和槽函数返回值是 void
  •  信号只需要声明,不需要实现
  •  槽函数需要声明也需要实现
  •  槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
  •  使用 emit 在恰当的位置发送信号;
  •  使用connect()函数连接信号和槽。
  •  任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
  •  信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。
  •  如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。
例子:实现按钮操作1窗口跳转2窗口,2窗口回到1窗口

在这里插入图片描述
在这里插入图片描述
mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>
#include <QDebug>
#include <subwidget.h>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    QPushButton b1;
    SubWidget subwin;  //窗口2


    void win_hide();
    void win_show();

};

#endif // MAINWINDOW_H

subwidget.h

#ifndef SUBWIDGET_H
#define SUBWIDGET_H

#include <QWidget>
#include <QPushButton>

class SubWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SubWidget(QWidget *parent = 0);
    QPushButton* b2 = new QPushButton;
    QPushButton* b3 = new QPushButton;

    void myslot();
signals:
    // 自定义信号, 必须使用signals 声明
    void sigSub();
    //void sigSub(int , QString);
    /*
     * 1. 可以有参数
     * 2. 可以重载
     * 3. 返回值为void
     * 4. 发送信号: emit + 信号名;
     * emit sigsub();
    */

public slots:
};

#endif // SUBWIDGET_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    b1.setParent(this);
    b1.setText("下一步");
    b1.resize(70,35);
    b1.move(100,100);
    this->resize(600,400);

    //由mainwin到subwin
    connect(&b1,&QPushButton::clicked,this,&MainWindow::win_hide);  //点击下一步到下一个窗口

    //由subwin回到mainwin
    //void (SubWidget::*MySigSub)() = &SubWidget::sigSub; //sigSub若有函数重载需要加上这句话指定是哪个函数,比如现在这句指定无参的那个函数
    connect(&subwin,&SubWidget::sigSub,this,&MainWindow::win_show);  //收到sigSub信号,则执行win_show函数

    setWindowTitle("step_1");
}

MainWindow::~MainWindow()
{

}

void MainWindow::win_hide()
{
    // 隐藏自己
    hide();
    // 显示下一个窗口
    subwin.show();
}

void MainWindow::win_show()
{
    // 显示自己
    show();
    // 隐藏上一个窗口
    subwin.hide();
}

subwidget.cpp

#include "subwidget.h"

SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
    b2->setParent(this);
    b2->setText("上一步");
    b2->move(100,100);
    this->resize(600,400);
    connect(b2,&QPushButton::clicked,this,&SubWidget::myslot); //按下“上一步按键则执行myslot函数,发送信号

    b3->setParent(this);
    b3->setText("退出");
    b3->move(200,100);
    connect(b3,&QPushButton::clicked,this,&SubWidget::close);

    setWindowTitle("step_2");
}

void SubWidget::myslot()
{
    emit sigSub();  //发送信号
}

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐