自定义信号和槽
信号和槽的本质都是函数。
区别:
信号必须由signal关键字来声明
信号可以重载
信号没有返回值,但可以有参数。由于信号都是没有返回值,所以,槽函数一定没有返回值
信号就是函数的声明,只需声明,无需定义。槽既要函数声明也要完成定义。
使用方式:emit MySignal();
例子说明:本例创建两个独立的窗口,分别在窗口中放置一个按钮,由此来进行两个窗口的切换。如:“切换到子窗口”,即子窗口显示,主窗口隐藏。反之亦然。
按照之前的方式创建程序,另外在项目中“添加新文件”->“C++ class”,名为csubwnd。即创建两个类,作为主窗口(widget)和子窗口(csubwnd)。
思路:
创建两个类,主窗口类来处理窗口的切换,本来只显示窗口,当收到子窗口发出的信号后,立即显示子窗口并隐藏主窗口。而子窗口类只负责发出信号。
自定义信号
一定要在Signal中声明(头文件中)。
signals:
void MySignal();
使用方式:
connect(&subPush,&QPushButton::released,this,&CSubWnd::MySlot);
void CSubWnd::MySlot()
{
emit MySignal();
}
其中MySlot()是自定义槽函数(具体见上一节内容)。emit MySignal()代表发出信号。
解析:当按钮subPush被释放时,this(本窗口)立即调用槽函数(MySlot)发出信号(MySignal)。由此可以看到,信号只需声明无需定义,槽函数既要声明也要定义。
主窗口的信号处理:
void Widget::Base()
{
//主窗口隐藏
this->hide();
//子窗口显示
subWnd.show();
}
void Widget::Sub()
{
//主窗口显示
this->show();
//子窗口隐藏
subWnd.hide();
}
{
//激活槽函数,切换到子窗口
connect(&push,&QPushButton::released,this,&Widget::Base);
//接受子窗口的信号,切换到主窗口
connect(&subWnd,&CSubWnd::MySignal,this,&Widget::Sub);
}
其中,push代表“切换到子窗口”按钮,subWnd代表“切换到主窗口”的按钮,MySignal是子窗口发出的信号。Base和Sub是两个用于切换窗口的槽函数。
带参数的信号
前面说过信号啊可以重载,下面重载一个带参数的信号。
信号声明:
signals:
//自拟信号
void MySignal();
void MySignal(int ,QString);
调用信号:
void CSubWnd::MySlot()
{
//发出自拟信号
emit MySignal();
emit MySignal(2018,"I am learnning Qt,我学习QT");
}
槽函数定义:
void Widget::TextSignal(int nNum,QString strChar)
{
qDebug()<<nNum<<strChar;
}
注意:信号和槽函数的参数必须一致,如信号void MySignal(int ,QString),即槽函数TextSignal也必须两个参数,且为类型为int和Qstring。
补充:
qDebug()是输出函数,类似于C++中的cout。qDebug()的头文件是<QDebug>,但使用时要注意qDebug(),q是小写,并且带上括号。
信号与槽函数的使用:
//Qt5版本带参数的信号
void (CSubWnd::*NoSub)()=&CSubWnd::MySignal;
connect(&subWnd,NoSub,this,&Widget::Sub);
void (CSubWnd::*Sub)(int,QString)=&CSubWnd::MySignal;
connect(&subWnd,Sub,this,&Widget::TextSignal);
问题:为什么要使用函数指针,而不是直接信号本身,如下:
connect(&subWnd, &CSubWnd::MySignal,this,&Widget::Sub);
connect(&subWnd, &CSubWnd::MySignal,this,&Widget:: TextSignal);
原因:
在前面的信号声明。 void MySignal();void MySignal(int ,QString);使用的是重载,如果直接信号名,会产生二义性,编译器无法获取发出的信号是哪一个?带参数还是不带参数。
当然,也有一种简便方式.
//Qt4版本,与Qt5使用函数指针效果等价
connect(&subWnd,SIGNAL(MySignal()),this,SLOT(Sub()));
connect(&subWnd,SIGNAL(MySignal(int,QString)),this,SLOT(TextSignal(int,QString)));
注意:如果使用Qt4版本。SINAL,SLOT都是宏。
- SINAL,SLOT将函数名字转换成字符串,不进行错误检查,如:SIGNAL(MySigl()),拼写错误了,编译器也会通过,但是会在执行的过程中才中断报错。
- 槽函数必须使用slots关键字来声明,否则无法识别,会报出无法寻查该函数。
public slots:
void Base(); //切换到子窗口
void Sub(); //切换到主窗口
void TextSignal(int ,QString); //测试带参数信号
补充:输出编码问题
qDebug()<<nNum<<strChar;
当string=“我学习QT",可能会输出u6211u662Fu5B32u3291.二进制编码
解决方法:
qDebug()<<nNum<<strChar.toUtf8().data();
解析
strChar.toUtf8()->字节数组QbyteArray
…data()->QbyteArray->char*.
此时就可以输出中文了。也可以是其他类型的编码。可以在qt编译器->工具->选项->文本编辑器.可以查看当前自己的编码类型。
源代码:
csubwnd.h
#ifndef CSUBWND_H
#define CSUBWND_H
#include <QWidget>
#include <QPushButton>
class CSubWnd : public QWidget
{
Q_OBJECT
public:
explicit CSubWnd(QWidget *parent = 0);
//发出信号的槽函数
void MySlot();
signals:
//自拟信号
void MySignal();
void MySignal(int ,QString);
public slots:
private:
//按钮
QPushButton subPush;
};
#endif // CSUBWND_H
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include "csubwnd.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
public slots:
void Base(); //切换到子窗口
void Sub(); //切换到主窗口
void TextSignal(int ,QString); //测试带参数信号
private:
Ui::Widget *ui;
QPushButton push;
//子窗口类
CSubWnd subWnd;
};
#endif // WIDGET_H
csubwnd.cpp
#include "csubwnd.h"
CSubWnd::CSubWnd(QWidget *parent) :
QWidget(parent)
{
this->setWindowTitle("子窗口");
subPush.setParent(this);
subPush.setText("切换到主窗口");
this->show();
//点击按钮后,利用槽函数发出信号
connect(&subPush,&QPushButton::released,this,&CSubWnd::MySlot);
resize(400,300);
}
void CSubWnd::MySlot()
{
//发出自拟信号
emit MySignal();
emit MySignal(2018,"I am learnning Qt,我学习QT");
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("主窗口");
push.setText("切换到子窗口");
push.setParent(this);
//激活槽函数,切换到子窗口
connect(&push,&QPushButton::released,this,&Widget::Base);
//接受子窗口的信号,切换到主窗口
// connect(&subWnd,&CSubWnd::MySignal,this,&Widget::Sub);
//Qt5版本带参数的信号
//void (CSubWnd::*NoSub)()=&CSubWnd::MySignal;
//connect(&subWnd,NoSub,this,&Widget::Sub);
//void (CSubWnd::*Sub)(int,QString)=&CSubWnd::MySignal;
//connect(&subWnd,Sub,this,&Widget::TextSignal);
//Qt4版本,与Qt5使用函数指针效果等价
connect(&subWnd,SIGNAL(MySignal()),this,SLOT(Sub())); connect(&subWnd,SIGNAL(MySignal(int,QString)),this,SLOT(TextSignal(int,QString)));
//设置窗口大小
resize(400,300);
}
Widget::~Widget()
{
delete ui;
}
void Widget::Base()
{
//主窗口隐藏
this->hide();
//子窗口显示
subWnd.show();
}
void Widget::Sub()
{
//主窗口显示
this->show();
//子窗口隐藏
subWnd.hide();
}
void Widget::TextSignal(int nNum,QString strChar)
{
qDebug()<<nNum<<strChar.toUtf8().data();
}