Qt訊號槽源碼剖析(一)

  • 2021 年 4 月 10 日
  • 筆記

大家好,我是IT文藝男,來自一線大廠的一線程式設計師

大家在使用Qt開發程式時,都知道怎麼使用Qt的訊號槽,但是Qt訊號槽是怎麼工作的? 大部分人仍然不知道;也就是說大家只知道怎麼使用,卻不知道基於什麼原理,顯然這是不符合深層次發展的;那麼今天我就給大家基於Qt源碼以及示例程式碼深度剖析Qt的訊號槽機制,一定會對大家有幫助。

基本概念

訊號

當對象改變其狀態時,訊號就由該對象發射 (emit) 出去,而且對象只負責發送訊號,它不知道另一端是誰在接收這個訊號。

槽

用於接收訊號,而且槽只是普通的對象成員函數。一個槽並不知道是否有任何訊號與自己相連接。

訊號與槽的連接

QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, 
const QObject *receiver, const char *method, 
Qt::ConnectionType type = Qt::AutoConnection)

通過QObject::connect靜態函數建立連接;其中sender與receiver是指向對象的指針,signal與method分別通過SIGNAL()與SLOT()宏來進行轉換。

元對象編譯器

MOC, the Meta Object Compiler。
Qt程式在交由標準編譯器(例如MSVC)編譯之前,先使用moc分析cpp頭文件;如果它發現在一個頭文件中包含了Q_OBJECT宏,則會生成另外一個cpp源文件(moc_文件名.cpp),該cpp源文件中包含了Q_OBJECT宏的實現、運行時資訊(反射)等。因此Qt程式的完整編譯過程為moc->預處理->編譯->鏈接

示例程式碼

Counter.h文件

#pragma once
#include <QtCore/QObject>

class Counter : public QObject
{
    Q_OBJECT

public:
    Counter();

public:
    int value() const;

public slots:
    void setValue(int value);

signals:
    void valueChanged(int newValue);

private:
    int m_value;
};

Counter.cpp文件

#include "Counter.h"

Counter::Counter():m_value(0)
{
}

int Counter::value() const
{
    return m_value;
}

void Counter::setValue(int value)
{
    if (value != m_value)
    {
        m_value = value;
        emit valueChanged(value);
    }
}

main.cpp文件

#include <QtCore/QCoreApplication>
#include "Counter.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Counter counterA;
    Counter counterB;
    QObject::connect(&counterA, SIGNAL(valueChanged(int)), 
    			     &counterB, SLOT(setValue(int)));

    counterA.setValue(10);//counterA.value()=10, counterB.value()=10
    counterB.setValue(20);//counterA.value()=10, counterB.value()=20

    return a.exec();
}

Qt宏

宏定義在qobjectdefs.h文件中(位於QtCore目錄)

signals

slots

Q_OBJECT

emit

SIGNAL

SLOT

Qt訊號槽源碼剖析系列會分拆為多個具體的細緻講解,後續我會一一分析並發布

今天就講解到這裡,更詳細的原理分析與講解,請關注微信公眾號(itwenyinan),觀看對應的的影片版講解;謝謝

Tags: