《Qt5:訊號和槽使用示例》

歐陽磊發表於2019-04-18

訊號和槽介紹 


訊號和槽用於物件之間的通訊。訊號和槽機制是Qt的核心功能,是與其他框架提供的功能最不同的部分。

在GUI程式設計中,當更改了某個視窗部件的狀態時,需要通知另外一個視窗部件做出相應的操作。例如,如果點選了“關閉按鈕,軟體需要呼叫close()函式來關閉當前視窗。

其它開發工具可能使用回撥實現這種通訊,回撥是指向函式的指標,因此如果希望處理函式通知您某些事件,則將指標傳遞給處理函式的另一個函式(回撥),然後處理函式在適當時呼叫回撥。但回撥不直觀,並且在確保回撥引數的型別正確性方面存在問題。

我們通常使用的是訊號和槽是一一對應的,其實也可以一對多。

訊號

Qt內部自帶了各種視窗部件的訊號,最常見的就是按鈕的clicked()。但是也可以自己宣告訊號,宣告訊號需要使用signals關鍵字,在signals前面不能用public、private和protected等限定符,訊號預設是public函式,可以從任何地方進行發射。

: 

槽就是普通的C++函式,可以像一般的函式一樣使用。宣告槽函式要使用slots關鍵字,可以是private、public或者protected型別的,槽也可以被宣告為虛擬函式。它最大的特點就是可以和訊號關聯,這是其它函式比不了的。

訊號和槽使用注意事項

1、需要繼承自QObject或其子類;

2、 使用訊號和槽必須在類宣告的最開始處新增Q_OBJECT巨集;

3、槽中引數型別要和訊號引數的型別相對應,且不能比訊號的引數多;

4、訊號只有宣告,沒有定義,且返回值為void型別;

5、槽有宣告,也有定義。

訊號和槽的關聯

訊號和槽關聯使用的是QObject類的connect()函式,需要注意的是,connect()函式中訊號和槽的引數只能為型別,不能有變數名。

Qt5版本函式原型

static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
                        const QObject *receiver, const QMetaMethod &method,
                        Qt::ConnectionType type = Qt::AutoConnection);

第一個引數:發射訊號的物件

第二個引數:發射的訊號

第三個引數:接受訊號的物件

第四個引數:要執行的槽

第五個引數:訊號和槽的關聯方式,預設為自動關聯

 Qt5版本使用示例

connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::closeWindow);

Qt4版本函式原型

static QMetaObject::Connection connect(const QObject *sender, const char *signal,
                        const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);

 Qt4版本使用示例

connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(closeWindow()));

兩個版本的區別

Qt4的SIGNAL和SLOT兩個巨集實際上是將其引數轉換為相應的字串。在編譯之前,Qt的moc工具從原始碼中提取出所需的後設資料,形成一張由使用了signals和slots修飾的所有函式組成的字串表。connect函式將與訊號關聯起來的槽的字串,同這張字串表中的資訊比較,從而知道在發出訊號時知道需要呼叫哪個槽函式。

這種訊號和槽的語法造成了兩個問題:

1、沒有編譯器檢查;

2、無法使用相容型別的引數。

為了解決這兩個問題,Qt5對訊號和槽的語法進行了改進。傳送訊號的型別是Sender,接受訊號的型別是Receiver。改進後的優點如下所示:

1、支援編譯期檢查。訊號和槽的拼寫檢查、引數匹配檢查。

2、支援相容型別引數的自動轉換。支援使用typedef或者名稱空間,還支援使用隱式型別轉換。

3、允許連線到任意函式。

儘管新版本有所改進,但是Qt4的語法還是可以用在Qt5的程式碼中的。

 

訊號和槽使用示例


1、開啟Qt Creator開發工具,新建一個Qt Widgets Application專案,在主視窗上新增一個pushButton按鈕。

2、新增Q_OBJECT巨集:使用訊號和槽必須在類宣告的最開始處新增Q_OBJECT巨集,一般自己生成。

Q_OBJECT

3、宣告槽函式:和宣告普通的成員函式差不多,只不過多了一個slots關鍵字

private slots:
    void closeWindow();

4、在mainwindow.cpp中新增如下程式碼,實現的功能是點選一下“關閉視窗”按鈕,就呼叫槽,關閉主視窗,相當於執行了視窗右上角那個紅叉的操作。

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle(tr("訊號和槽"));
    ui->pushButton->setText(tr("關閉視窗"));
    //Qt5
    connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::closeWindow);
    //Qt4
    //connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(closeWindow()));
}

//關閉視窗
void MainWindow::closeWindow()
{
    close();
}

MainWindow::~MainWindow()
{
    delete ui;
}

效果圖

還可以通過Qt Designer新增訊號槽,選中按鈕點選滑鼠右鍵,選擇“轉到槽”,進入“轉到槽”頁面,選擇一個訊號,系統會自動生成相應的槽函式on_pushButton_cliceked(),由字串on、部件的物件名和訊號名稱三部分組成,因此如果使用者自定義槽,就不允許使用此種命名方式,以免衝突,此種方法新增訊號槽不需要使用關聯函式。

相關文章