天天看点

Qt中的信号与槽概述使用

参考书籍:《Qt学习之路》&《Qt Creator快速入门》

概述

信号和槽用于两个对象之间的通信。信号和槽机制是Qt的核心特征,也是Qt不同于其它开发框架的最突出特征。熟练使用和理解信号槽,能够设计出解耦的程序。

信号槽实际就是观察者模式。当某个事件发生时,对象就会发出一个信号(signal)。这种发出是没有目的的,类似于广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,用自己的一个函数(称为槽(slot))来处理这个信号。

使用

为了使用信号槽,必须继承QObject。凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT。这是一个宏,在预处理器之前展开。

一般形式:

//Qt5
connect (sender, signal, receiver, slot);
           

QObject::connection()的五个重载:

QMetaObject::Connection connect (const QObject *, const char *, const QObject *, const char *, Qt::ConnecionType);

QMetaObject::Connection connect (const QObject *, const QMetaObject &, const QObject *, const QMetaObject &, Qt::ConnecionType);

QMetaObject::Connection connect (const QObject *, const char *,  const char *, Qt::ConnecionType) const;

QMetaObject::Connection connect (const QObject *, PointerToMemberFunction, const QObject *,PointerToMemberFunction, Qt::ConnecionType);

QMetaObject::Connection connect (const QObject *, PointerToMemberFunction, Functor);
           

借助Qt5的信号槽语法,可以将一个对象的信号连接到Lambda表达式:

// !!! Qt 5
#include <QApplication>
#include <QPushButton>
#include <QDebug>

int main(int argc, char *argv[])
{ 
	QApplication app(argc, argv);
	QPushButton button("Quit");
	QObject::connect(&button, &QPushButton::clicked, [](bool) {
		qDebug() << "You clicked me!";
	});
	button.show();
	return app.exec();
}
           

自定义信号槽

//!!! Qt5
#include <QObject>
// newspaper.h

class Newspaper : public QObject
{
	Q_OBJECT
public:
	Newspaper(const QString & name) :
	m_name(name)
	{
	}
	void send()
	{
		emit newPaper(m_name);
	}
	
signals:
	void newPaper(const QString &name);
	
private:
	QString m_name;
};


// reader.h
#include <QObject>
#include <QDebug>

class Reader : public Q Object
{
	Q_OBJECT
public:
	Reader() {}
	
	void receiveNewspaper(const QString & name)
	{
		qDebug() << "Receives Newspaper: " << name;
	}
}; 


// main.cpp
#include <QCoreApplication>
#include "newspaper.h"
#include "reader.h "

int main(int argc, char *argv[])
{
	QCoreApplication app(argc, argv);
	Newspaper newspaper("Newspaper A");
	Reader reader;
	QObject::connect(&newspaper, &Newspaper::newPaper, &reader, &Reader::receiveNewspaper);
	newspaper.send();
	return app.exec();
}
           

signals块所列出的,就是该类的信号。信号就是一个个的函数名,返回值是void(因为无法获得信号的返回值,所以也就无需返回任何值),参数是该类需要让外界知道的数据。信号作为函数名,不需要在cpp函数中添加任何实现(我们曾经说过,Qt程序能够使用普通的make进行编译。没有实现的函数名怎么会通过编译?原因还是在moc,moc会帮我们实现信号函数所需要的函数体,所以说,moc 并不是单纯的将 Q_OBJECT展开,而是做了很多额外的操作)。

自定义信号槽需要注意的事项:

o 发送者和接收者都需要是 QObject 的子类(当然,槽函数是全局函数、Lambda表达式等无需接收者的时候除外);

o 使用signals标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;

o 槽函数是普通的成员函数,作为成员函数,会受到public、private、protected 的影响;

o 使用 emit 在恰当的位置发送信号;

o 使用 QObject::connect()函数连接信号和槽。

o 槽中参数的类型要和信号参数的类型相对应,且不能比信号的参数多。信号中多余的参数将被忽略。

在调用connect()函数时,信号和槽的参数只能有类型,不能有变量名。

此外,还可以用disconnection()来断开关联:

QObject::disconnect(const QMetaObject::Connect &connection);
           
Qt

继续阅读