Qt--訊號與槽機制
一、什麼是訊號槽機制
訊號槽機制是Qt的核心特性,是對C/C++的拓展,應用於物件與物件之間的通訊。訊號槽的處理依賴於moc(Meta Object Compiler)工具。
訊號槽機制很好地完成了介面操作的響應,類似於MFC和matlab GUI中的callback函式。訊號與槽會通過connect函式進行連線,訊號會在某種情況或者動作下由某個物件發射,連線了該訊號的槽會接收到該訊號,然後執行相應的操作。
二、訊號槽機制的連線方式
比較常用的連線方式是,物件A發射訊號,物件B的槽函式接收訊號做出響應。函式原型:QMetaObject::Connection connect (const QObject *, const char*, const QObject*, const char*, Qt::ConnectionType)。一般只使用前面的四個引數,即connect(sender, signal, receiver, slot)。sender傳送signal,然後receiver的slot接收訊號。
以下舉個小例子,點選按鈕關閉視窗。
建立Qt Widgets Application,基於QMainWindow類,不包含ui檔案。修改MainWindow建構函式如下:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QPushButton *btn1 = new QPushButton(tr("Close"));//建立一個按鈕控制元件 QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(btn1, 1, Qt::AlignCenter);//將按鈕新增到佈局管理器中 QWidget *mainWidget = new QWidget(this); mainWidget->setLayout(mainLayout); this->setCentralWidget(mainWidget);//將新建的mainWidget作為MainWindow的主widget connect(btn1, SIGNAL(clicked(bool)), this, SLOT(close()));//按鈕btn1被點選時發射訊號,視窗MainWindow接收到訊號時呼叫close()函式,關閉視窗。 }
程式執行結果如下:
點選Close按鈕,視窗關閉。
訊號與槽除了以上介紹的最普遍的連線方式外,還有以下常見的連線方式:
(1)一個訊號與多個槽連線
(2)一個槽與多個訊號連線
其中,一個訊號與多個槽連線,當該訊號發射時,與其連線的槽會一一執行,但是執行的順序是隨機的,不能人為指定槽的執行順序。
當想斷開訊號與槽的連線時,可以使用以下方法:
(1)斷開與物件A相關的所有連線
disconnect(ObjectA, 0, 0, 0);
(2)斷開與訊號A相關的所有連線
disconnect(ObjectA, SignalA, 0, 0);
(3)斷開物件A和物件B的連線
disconnect(ObjectA, 0, ObjectB, 0);
三、自定義訊號和槽
Qt訊號槽機制除了可以使用物件自帶的訊號和槽之外,還可以自定義訊號函式和槽函式,為介面設計提供了方便和靈活性。
為了使用自定義的訊號和槽,包含自定義訊號和槽的類必須繼承於QObject類或者其子類,包括Q_OBJEDT巨集定義。Q_OBJECT巨集必須出現在類定義的第一行,它的展開用於啟動元物件的特性,其中就包括訊號槽特性。
自定義訊號:自定義訊號寫在標頭檔案宣告中,用Signals關鍵字來指出進入訊號函式宣告區。訊號函式的宣告形式上和普通函式一樣,但是訊號函式沒有返回值(即返回值為void),有引數,但是引數不能有預設引數。另外,訊號函式沒有函式體定義。
自定義槽:自定義槽同樣寫在標頭檔案宣告中,用Slots關鍵字來指出進入槽函式宣告區。槽函式和類普通的成員函式一樣有宣告和定義,但是同樣不能有預設引數。槽函式可以加private、protected、public來限制與之相連線的訊號。
以下舉個自定義訊號和槽的例子:
建立Qt Widgets Application,基於QMainWindow類,不包含ui檔案。MainWindow類新增槽函式showWarning(QStirng)。工程新增C++類Warning類,Warning類繼承於QObject,包含warning訊號。
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void showWarning(QString message);
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QMessageBox>
#include "warning.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
Warning myWarning(QString("It is too hot!"));
connect(&myWarning, SIGNAL(warning(QString)), this, SLOT(showWarning(QString)));//將Warning類的訊號warning(QString)與MainWindow的槽showWarning(QString)相連線
myWarning.sendWarning();//發射訊號
}
void MainWindow::showWarning(QString message)
{
QMessageBox::information(this, tr("QMessageBox::information()"), message);
}
MainWindow::~MainWindow()
{
}
warning.h
#ifndef WARNING_H
#define WARNING_H
#include <QObject>
class Warning : public QObject
{
Q_OBJECT
private:
QString message;
public:
Warning(QString myMessage);
void sendWarning()
{
emit warning(message);
}
signals:\
void warning(QString message);
};
#endif // WARNING_H
warning.cpp
#include "warning.h"
Warning::Warning(QString myMessage)
{
message = myMessage;
}
程式執行結果如下:
四、訊號槽機制的優點簡述
1. 型別安全
需要關聯的訊號和槽的簽名必須是等同的,即訊號函式的引數型別和個數和槽函式的引數型別和個數應該是相同的,不過槽函式的引數個數可以少於訊號函式的引數個數,但是少的引數必須是最後的引數。如果訊號函式和槽函式的簽名不一致,則編譯會出錯。
2. 鬆耦合
Qt提供的訊號槽機制,使得訊號的傳送者不需要知道接收槽屬於哪個物件,而只需要負責在適當的時候或情況下發送訊號;而接收訊號的物件同樣不需要知道有哪些訊號關聯了自己的槽函式。connect函式決定了哪些訊號與哪些槽相連線。
3. 靈活性
Qt提供的訊號槽機制允許使用者自定義訊號和槽,而且訊號與槽的連線為多對多連線,即一個訊號可以連線多個槽,一個槽同樣可以連線多個訊號,這使得介面設計更加方便靈活。
本文參考了陸文周主編的《Qt 5--開發及例項》(第2版)以及以下網址:
1. QT的訊號與槽機制介紹點選開啟連結
2. Qt學習之路2:訊號槽 | DevBean Tech World點選開啟連結
其中“QT的訊號與槽機制介紹”是一篇很不錯的文章,包含很多細節問題,例如訊號和槽函式在定義時需要注意的細節。