【QT】3_2_1_Qt自定义信号和槽

作者:永恒0852永恒0852发布时间:2017-11-13 22:16
1.自定义槽函数
        1)槽和普通的成员函数几乎是一样的,也会受到 public、protected、private 等访问控制符的影响,也可像普通成员函数直接调用。 (我们这里新建一个无ui的工程)

                  1.png

            a)在头文件.h中定义按钮及槽函数

            b)在头文件对应的cpp文件中实现按钮和槽函数

                     2.png

        2)在Qt4中,槽函数需要在函数声明前加入slots关键字。

public slots: //QT4的槽函数,必须指定时slots
void myMin();

        3)在Qt5 中,任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数。

public: //QT5的槽函数,也是一个普通的函数
void myClose();

        4)执行结果

            a)运行界面:

3.png

            b)点击QT5:窗口关闭,并输出下面的调试信息                    4.png

            c)点击QT4:窗口最小化,并输出下面的调试信息                    5.png

        5)总结:

            a)槽函数也是函数,都是没有返回值
            b)如果信号没有参数,那么槽函数就没有参数(一一对应的关系,可以是任意类型)
            c)qt5, 可以是普通任意函数
            d)qt 4, 槽函数,必须有slot声明,且在代码输入是没有提示,输入错误时,无法明确提示是哪个地方的错误。(例如连接函数,需要对p取地址,但如果你没有取地址,会报错,但错误指向了其他的地方。)
        

        6)工程代码:3_2_1_Qt自定义的信号和槽1.zip

2.自定义信号

        1)创建一个项目,实现两个独立窗口交互
            a)新建工程,第一个为BigWidget,其他的设置与之前的相似,直到创建一个完整的项目。
                  6.png
            b)在右击项目名称,如下图,名称为SilWidget,依次下一步,最后完成添加。
                  7.png
                  8.png
                  9.png
                  10.png
        2)实现窗口交互
            a)工程创建完后,点击运行编译,会弹出“大窗口"。
            b)此时还每出现“小窗口”,小窗口目前黑没有被定义成为一个对象。所以,我们在大窗口的头文件中,包含小窗口的头文件,在大窗口的类中,定义一个小窗口的成员,然后在大窗口的构造函数中,显示出小窗口。(其中设置大窗口的信息:名字“我是大窗口”,小窗口的信息:名字“我是小窗口”位置:500,200,设置位置是为了让两个窗口不重合。)
            c)此时在运行程序,结果如下,如图所示,为什么小窗口在下面,而大窗口在上面,那是因为大窗口在调用构造函数的时候,发现了自己有成员对象,所以需要调用成员对象的构造函数来创建成员对象,成员对象创建完成后,在调用自己的构造函数,故,小窗口先创建,大窗口后创建,所以大窗口在前面。
                  11.png
            d)我们在小窗口的构造函数加入一个成员数据,在大窗口上面使用按钮读取,点击按钮后的执行结果如下,在debug输出看到了小窗口的成员变量的值。
                   12.png
            e)既然大窗口上面可以读取小窗口的内容,那我们能不能在小窗口上直接读取到大窗口的成员变量的值呢?答案是不行,因为,小窗口数据大窗口的成员变量,所以大窗口可以直接调用小窗口的成员数据,但是小窗口中,且不能直接调用大窗口的数据,此时我们就用到了,自定义信号的功能,虽然小窗口上不能直接获取到大窗口的数据,但是可以发出一个信号,让大窗口来提供他的数据。
                 怎么自定义信号:
                  i:在头文件silwiget.h中 使用 signals声明这个信号。(类似声明函数一样,只声明,不实现)  
                        如下图,就是声明了4个信号(属于class SilWiget  ,窗体对象是:silw)                        13.png

                 ii:怎么使用信号:使用一个按钮的信号,来调用一个槽函数,发送这个信号。14.png

                iii:发送信号的槽函数,使用emit来发送这个自定义的信号。 

15.png

                    iii:对方怎么接受这个信号:接收信号的方式如下,当检测到,来自silw窗口发出的showBigW信号时,回调用自己的槽函数去处理。

16.png

        3)信号交互演示如下:小窗口获取大窗口的数据,都是通过信号传递的方式,让大窗口协助完成的想要操作。(GIF动画,如果不能播放,请点击打开图片)

16.gif


        4)使用总结
            a)自定义信号和槽注意事项
                发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
                使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
                槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
                使用 emit 在恰当的位置发送信号;
                使用QObject::connect()函数连接信号和槽;
                任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
            b)信号和槽的更多用法
                一个信号可以和多个槽相连,如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。
                多个信号可以连接到一个槽,只要任意一个信号发出,这个槽就会被调用。
                一个信号可以连接到另外的一个信号,当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
                槽可以被取消连接
                使用Lambda 表达式,在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。
        5)工程代码:
            a)06_Signal
QT += core gui
CONFIG += c++11
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = 06_Signal
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
main.cpp \
bigwidget.cpp \
silwiget.cpp

HEADERS += \
bigwidget.h \
silwiget.h

            b1)bigwidget.h

#ifndef BIGWIDGET_H
#define BIGWIDGET_H
#include <QWidget>
#include"silwiget.h"

class BigWidget : public QWidget
{
Q_OBJECT

public:
BigWidget(QWidget *parent = 0);
~BigWidget();
private:
SilWiget silw; //定义小窗口为大窗口的成员变量

public:
QPushButton retVal;
QPushButton showSil; //"显示小窗口,隐藏大窗口"
int tempVal; //大窗口的数据

//槽函数
void getSilval(); //槽函数,读取小窗口的数据
void getSilSig(int,QString); //响应小窗口的槽函数
void setSilSig(); //响应小窗口的槽函数,写入数据

void showSilWidget(); //显示小窗口,隐藏自己
void showBigWidget(); //显示大窗口,隐藏小窗口
};

#endif // BIGWIDGET_H

            b2)bigwidget.cpp

#include "bigwidget.h"

BigWidget::BigWidget(QWidget *parent)
: QWidget(parent)
{
//窗口设置
this->setWindowTitle("我是大窗口");
this->resize(200,100);
silw.show();
this->tempVal = 1234; //初始化变量

//按钮获取小窗口的成员的值
retVal.setText("获取小窗口数据");
retVal.setParent(this); //指定父对象
retVal.move(10,10); //设置位置
connect(&retVal,&QPushButton::pressed,this,&BigWidget::getSilval); //获取小窗口的函数。

//槽函数,响应小窗口的信号
//大窗口接收小窗口的信号
//connect(&silw,&SilWiget::testSignal02,this,&BigWidget::getSilSig); //获取小窗口的信号
connect(&silw,&SilWiget::testSignal01,this,&BigWidget::setSilSig); //小窗户获取大窗口的值

//显示小窗口
showSil.setText("显示小窗口,隐藏大窗口");
showSil.setParent(this);
showSil.move(10,40);
connect(&showSil,&QPushButton::pressed,this,&BigWidget::showSilWidget);

//接收小窗口的显示大窗口隐藏小窗口的信号
connect(&silw,&SilWiget::showBigW,this,&BigWidget::showBigWidget);

//使用指针的方式获取数据
connect(&silw,&SilWiget::testSignal03,
[=](int *a)
{
cout <<"大窗口响应";
*a = 66666;
}

);
}

void BigWidget::getSilval() //实现槽函数,打印小窗口的数据
{
cout<<silw.tempdata;
}

void BigWidget::getSilSig(int a,QString str) //实现响应小窗口的槽函数
{
cout<<str<<" a="<<a;
}

void BigWidget::setSilSig() //实现响应小窗口的信号,把大窗口的数据写入小窗口的成员
{
cout<<"大窗口收到,数据已经写入!";
silw.tempVal = this->tempVal;
}
void BigWidget::showSilWidget() //显示小窗口,隐藏自己
{
this->hide();
silw.show();
}


void BigWidget::showBigWidget() //显示大窗口,隐藏小窗口
{
this->silw.hide();
this->show();
}

BigWidget::~BigWidget()
{

}
            c1)silwiget.h
#ifndef SILWIGET_H
#define SILWIGET_H
#include <QWidget>
#include<QString>
#include <QPushButton>
#include <QDebug>
#define cout qDebug()

class SilWiget : public QWidget
{
Q_OBJECT
public:
explicit SilWiget(QWidget *parent = nullptr);

signals: //定义信号,信号是函数的声明,不用实现。
void testSignal01(); //无参信号
void testSignal02(int,QString); //有参信号
void showBigW(); //发出信号,“显示大窗口,隐藏小窗口"
void testSignal03(int *);

public:
int tempdata; //小窗口的数据变量
int tempVal; //保存接收大窗口的数据
QString str;

private:
QPushButton getVal; //小窗口的按钮,发送获取数据信号
QPushButton getBigVal; //小窗口的按钮,输出获取到的数据

QPushButton showBig; //"显示大窗口,隐藏小窗口"
QPushButton gettemp; //获取大窗口的数据

public:
//槽函数
void emitSignal();
void outBigVal(); //输出获取到的内容
void emitShowBig(); //发送"显示大窗口,隐藏小窗口"
void seedp();

};

#endif // SILWIGET_H

            c2)silwiget.cpp  

#include "silwiget.h"

SilWiget::SilWiget(QWidget *parent) : QWidget(parent)
{
    //窗口初始设置
    this->setWindowTitle("我是小窗口");
    this->resize(200,200);
    this->move(800,500);
    this->tempdata = 100;   //初始化成员变量
    this->tempVal = 0;

    //向大窗口发送信号
    getVal.setText("获取大窗口的数据"); //发送信号
    getVal.setParent(this); //指定父对象
    getVal.move(10,10);
    connect(&getVal,&QPushButton::pressed,this,&SilWiget::emitSignal);  //按下按钮产生的信号,有当前窗口处理,执行发送槽函数

    //打印自己的成员变量的值
    getBigVal.setText("打印获取到的结果");
    getBigVal.setParent(this);
    getBigVal.move(10,40);
    connect(&getBigVal,&QPushButton::pressed,this,&SilWiget::outBigVal); //输出获取的内容

    //显示大窗口
    showBig.setText("显示,大窗口,隐藏小窗口");
    showBig.setParent(this);
    showBig.move(10,100);
    connect(&showBig,&QPushButton::pressed,this,&SilWiget::emitShowBig);

    //指针方式获取大窗口的数据
    gettemp.setText("获取大窗口的数据(指针方式)"); //发 送信号
    gettemp.setParent(this); //指定父对象
    gettemp.move(10,70);
    connect(&gettemp,&QPushButton::pressed,this,&SilWiget::seedp);  //按下按钮产生的信号,有当前窗口处理,执行发送槽函数
}

void SilWiget::emitSignal()     //发送信号的槽函数
{
    qDebug()<<"小窗口正在呼叫大窗口:";
    emit testSignal01();        //要求大窗口把他的数据写入小窗口的成员变量
    //emit testSignal02(555,"我是小窗口");
}

void SilWiget::outBigVal()          //显示获取大窗口的数据
{
    qDebug()<<"tempVal = "<<tempVal;
}

void SilWiget::emitShowBig()        //发送显示大窗口的信号
{
    emit showBigW();
}

void SilWiget::seedp()          //发送信号的槽函数
{
    emit testSignal03(&tempVal);//获取大窗口的数据
}

            d)main.cpp

#include "bigwidget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
BigWidget w;
w.show();

return a.exec();
}

        6)完整的代码(注意解压后不能有中文路径) 3_2_1_Qt自定义的信号和槽2.zip

/*************************************************************
*   温馨提示:
*            为了不影响文章的可读性,本站图片均不自动加水印。
*            除非注明,文章均由"永恒0852"整理发布,欢迎转载。
*            否则转载请注明本文地址:http://www.yongheng0852.com/qt/44.html
**************************************************************/



评论