1,信号槽是 Qt 框架引以为豪的机制之一, 所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(称为槽(slot))来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。(这里提一句,Qt 的信号槽使用了额外的处理来实现,并不是 GoF 经典的观察者模式的实现方式。) ,信号槽机制的实现在QObject中。
connect(&b1, &QPushButton::pressed, this, &MainWidget::close);
/* &b1: 信号发出者,指针类型
* &QPushButton::pressed:处理的信号, &发送者的类名::信号名字
* this: 信号接收者
* &MainWidget::close: 槽函数,信号处理函数 &接收的类名::槽函数名字
*/
/* 自定义槽,普通函数的用法
* Qt5:任意的成员函数,普通全局函数,静态函数
* 槽函数需要和信号一致(参数,返回值)
* 由于信号都是没有返回值,所以,槽函数一定没有返回值
*/
(1)mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include
#include
#include "subwidget.h" //子窗口头文件
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
public slots:
void mySlot();
void changeWin();
void dealSub();
void dealSlot(int, QString);
private:
QPushButton b1;
QPushButton *b2;
QPushButton b3;
SubWidget subWin;
};
#endif
(2)mainwidget.cpp
#include "mainwidget.h"
#include
#include //打印
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
b1.setParent(this);
b1.setText("close");
b1.move(100, 100);
b2 = new QPushButton(this);
b2->setText("abc");
connect(&b1, &QPushButton::pressed, this, &MainWidget::close);
connect(b2, &QPushButton::released, this, &MainWidget::mySlot);
connect(b2, &QPushButton::released, &b1, &QPushButton::hide);
/* 信号:短信
* 槽函数:接收短信的手机
*/
setWindowTitle("老大");
//this->setWindowTitle("老大");
b3.setParent(this);
b3.setText("切换到子窗口");
b3.move(50, 50);
//显示子窗口
//subWin.show();
connect(&b3, &QPushButton::released, this, &MainWidget::changeWin);
//处理子窗口的信号
// void (SubWidget::*funSignal)() = &SubWidget::mySignal; //此处用函数指针实现函数重载。
// connect(&subWin, funSignal, this, &MainWidget::dealSub);
// void (SubWidget::*testSignal)(int, QString) = &SubWidget::mySignal;
// connect(&subWin, testSignal, this, &MainWidget::dealSlot);
//Qt4信号连接
//Qt4槽函数必须有slots关键字来修饰
connect(&subWin, SIGNAL(mySignal()), this, SLOT(dealSub()) );
connect(&subWin, SIGNAL(mySignal(int,QString)),
this, SLOT(dealSlot(int,QString)) );
// SIGNAL SLOT 将函数名字 -> 字符串 不进行错误检查
//Lambda表达式, 匿名函数对象
//C++11增加的新特性, 项目文件: CONFIG += C++11
//Qt配合信号一起使用,非常方便
QPushButton *b4 = new QPushButton(this);
b4->setText("Lambda表达式");
b4->move(150, 150);
int a = 10, b = 100;
//connnect lambda表达式是重点。
connect(b4, &QPushButton::clicked,
// = :把外部所有局部变量、类中所有成员以值传递方式
// this: 类中所有成员以值传递方式
// & : 把外部所有局部变量, 引用符号
[=](bool isCheck)
{
qDebug() << isCheck;
}
);
resize(400, 300);
}
void MainWidget::dealSlot(int a, QString str)
{
// str.toUtf8() -> 字节数组QByteArray
// ……data() -> QByteArray -> char *
qDebug() << a << str.toUtf8().data();
}
void MainWidget::mySlot()
{
b2->setText("123");
}
void MainWidget::changeWin()
{
//子窗口显示
subWin.show();
//本窗口隐藏
this->hide();
}
void MainWidget::dealSub()
{
//子窗口隐藏
subWin.hide();
//本窗口显示
show();
}
MainWidget::~MainWidget()
{
}
(3)subwidget.h
#ifndef SUBWIDGET_H
#define SUBWIDGET_H
#include
#include
class SubWidget : public QWidget
{
Q_OBJECT
public:
explicit SubWidget(QWidget *parent = 0);
void sendSlot();
signals:
/* 信号必须有signals关键字来声明
* 信号没有返回值,但可以有参数
* 信号就是函数的声明,只需声明,无需定义
* 使用:emit mySignal();
* 信号可以重载
*/
void mySignal();
void mySignal(int, QString);
public slots:
private:
QPushButton b;
};
#endif
4,subwidget.cpp
#include "subwidget.h"
SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("小弟");
b.setParent(this);
b.setText("切换到主窗口");
connect(&b, &QPushButton::clicked, this, &SubWidget::sendSlot);
resize(400, 300);
}
void SubWidget::sendSlot()
{
emit mySignal();
emit mySignal(250, "我是子窗口");
}
5,main.cpp
#include "mainwidget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;//执行MainWidget的构造函数
w.show();
return a.exec();
}