天天看點

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

繼續閱讀