QT Creator 快速入門教程 讀書筆記(三)

一   信號和槽

  GUI 程序除了要繪製控件,還要響應系統和用戶事件,例如重繪、繪製完成、點擊鼠標、敲擊鍵盤等。當事件發生時,UI 會產生相應的變化,讓用戶直觀地看到。
大部分編程(例如Win SDK、Web前端)中使用回調函數來響應事件,而 Qt 卻首創了信號和槽機制。所謂回調函數,就是程序員提早定義一個函數,當事件發生時就調用該函數。
信號和槽是Qt的核心,它讓兩個互不相干的對象鏈接起來,當一個對象的狀態改變時,能夠通知另外一個對象。
咱們先經過例子來演示一下信號和槽:前端

具體的代碼:程序員

#include "mainwindow.h"
#include <QApplication>
#include <QMainWindow>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QMainWindow w;
    w.setWindowTitle("微浪遊戲");
    w.resize(325, 120);

    QLineEdit lineEdit(&w);
    lineEdit.setGeometry(30, 20, 180, 36);
    lineEdit.setPlaceholderText("請輸入文本");

    QPushButton btn("取消", &w);
    btn.setGeometry(220, 20, 70, 36);

    QLabel label(&w);
    label.setGeometry(30, 70, 250, 30);

    //鏈接clicke()信號和quit()槽
    QObject::connect(&btn, SIGNAL(clicked()), &app, SLOT(quit()));
    //鏈接textChanged()信號和setText()槽
    QObject::connect(&lineEdit, SIGNAL(textChanged(QString)), &label, SLOT(setText(QString)));

    w.show();
    return app.exec();
}

 在上面的demo中建立了三個控件:lineEdit,btn,label,他們都是QMainWindow w的子控件。運行的結果以下:編程

點擊「取消」按鈕,程序就關閉了,這是第26行代碼的做用;在文本輸入框中輸入一段文本,下面的 Label 會隨時顯示出來,這是第28行代碼的做用。app

這兩個對象都是經過信號和槽鏈接起來的,信號和槽用於兩個對象之間的通訊。信號和槽是QT的核心特徵,當一個特殊的事情發生時即可以發射一個信號,好比demo中的取消按鈕被點擊時,就會發射clicked()信號;而槽就是一個函數,它在信號發射後被調用來響應這個信號,Qt的部件類中已經定義了一些信號和槽,可是更經常使用的作法是子類化部件,而後添加自定義的信號和槽來實現想要的功能。函數

信號是隻有函數聲明、沒有函數體的成員函數。槽是擁有完整函數體的普通成員函數,你能夠在槽函數中實現各類功能,與普通函數相比並無區別,例如 quit() 的做用就是退出程序。ui

connect() 是 QObject 類的靜態成員函數;QObject 是 Qt 中全部類的基類,它就像「樹根」,從這裏派生出了全部其餘「樹枝」。
須要注意的是,信號不是事件。當用戶點擊「取消」按鈕時,Qt 會捕獲該點擊事件,進行預處理,而後發射 clicked() 信號; clicked() 和 quit() 關聯起來了,接下來就會調用 quit() 函數。
信號和槽機制歸根結底也是回調函數,只不過繞了個圈子。在這種機制下,程序員有兩次處理事件的機會,一是在捕獲事件後發射信號前進行預處理(事件不符合預期能夠不發射信號),二是在槽函數中進行主要處理。
再來看第27行。textChange() 信號會在文本改變時發出,setText() 槽用來設置 Label 的文本,QString 是要傳遞的數據的類型。當用戶輸入文本時,lineEdit 會發出 textChange() 信號,該信號將攜帶數據,數據類型爲 QString,數據內容爲輸入的文本;setText() 槽接收到信號後先解析信號攜帶的數據,獲取用戶輸入的文本,而後填充到 Label 中。
spa

二 信號和槽的關聯

信號和槽的關聯使用的是QObject類的connect()函數,connect() 是 QObject 類的靜態成員函數,它有多個原型:指針

connect(QObject *sender,   char *signal,
        QObject *receiver, char *method);
connect(QObject *sender,   PointerToMemberFunction signal,
        QObject *receiver, PointerToMemberFunction method);
connect(QObject *sender,   PointerToMemberFunction signal,
        QObject *context,  Functor functor);
connect(QObject *sender,   QMetaMethod &signal,
        QObject *receiver, QMetaMethod &method);
connect(QObject *sender,   PointerToMemberFunction signal,  Functor functor);

 簡單起見,上面省略了 connect() 的返回值和最後一個參數,以及某些參數前面的 const 修飾符,讀者能夠在 Qt 幫助手冊中查看完整的原型。code

connect() 函數返回值類型爲 QMetaObject::Connection,表示當前鏈接句柄。最後一個參數爲 Qt::ConnectionType type = Qt::AutoConnection,表示鏈接類型,通常默認便可。

觀察上面的原型,除了最後一個有3個參數,其餘都有4個參數,其中:
1) sender 爲信號發送者,receiver 爲信號接收者,它們都是對象指針。

2) 第1個原型中,signal 爲信號,method 爲槽函數,它們都是字符串,必須藉助 SIGNAL() 和 SLOT() 將函數形式轉換爲字符串形式。SIGNAL() 和 SLOT() 是宏,而非函數。上面的示例中就使用了該原型,它是經常使用的原型,初學者必需要掌握。

3) 第2個原型中,PointerToMemberFunction 爲指向成員函數的指針。你能夠將示例中的代碼作以下更改:對象

QObject::connect(&btn, &QPushButton::clicked, &app, &QApplication::quit);
QObject::connect(&lineEdit, &QLineEdit::textChanged, &label, &QLabel::setText);

這是 Qt 5 新增的原型,能夠在編譯期間進行檢查,若是信號和槽不存在或者不匹配,則會報錯。而第1種原型是從 Qt 誕生以來一直支持的,不能在編譯期進行檢測,若是信號和槽有誤,只會在程序運行期間給出警告並返回 false,不容易發現問題,這是它的一個缺陷。因此在 Qt 5 中咱們鼓勵使用第2種原型。

相關文章
相關標籤/搜索