1. 程式人生 > >Qt signal-slot

Qt signal-slot

Qt的訊號和槽機制,使得兩個物件可以進行互動。得益於Qt的元物件系統,可以在Qt的help中查詢The Meta-Object System,它告訴我們如何使用該系統,進而使用訊號和槽以及屬性系統。

來自Qt help 文件
The meta-object system is based on three things:
1.The QObject class provides a base class for objects that can take advantage of the meta-object system.
2.The Q_OBJECT macro inside the private section of the class declaration is used to enable meta-object features, such as dynamic properties, signals, and slots.
3.The Meta-Object Compiler (moc) supplies each QObject subclass with the necessary code to implement meta-object features.

我們只需要繼承QObject或其子類,並使用巨集Q_OBJECT,signals下宣告訊號,xx slots下宣告槽函式即可。

使用時,我們提倡最新的語法,函式指標,而非字串。

// 1 繼承QObject
class Sender:public QObject{
    // 2 巨集,元物件系統
    Q_OBJECT
public:
    explicit Sender(QObject *parent = nullptr){}
    ~Sender(){}
    void sendData(){
        emit sig_sendData(10);
        // emit 關鍵字為空
        sig_sendData("hello");
        Data data; data.count = 20; data.str = "good";
        emit sig_sendCusData(data);
    }
signals:
    // 過載
    void sig_sendData(int data);
    void sig_sendData(QString data);

    // 自定義資料
    void sig_sendCusData(Data &data);
};
class Geter:public QObject{
    Q_OBJECT
public:
    explicit Geter(QObject *parent = nullptr){}
    ~Geter(){}

public slots:
    void slot_getData(int data);
    void slot_getData(QString data);
    void slot_getCusData(Data &data);
private slots:

};

連線

    Sender *pSender = new Sender;
    Geter *pGeter = new Geter;

    connect(pSender, static_cast<void(Sender::*)(int)>(&Sender::sig_sendData),
            pGeter,  static_cast<void(Geter::*)(int)>(&Geter::slot_getData));
    
    // 使用自定義資料,直連可以的,但是佇列時,涉及到copy等操作,需要註冊到元系統中
    qRegisterMetaType<Data>("Data");
    qRegisterMetaType<Data>("Data &");
    qRegisterMetaType<Data>("Data *");
    connect(pSender, &Sender::sig_sendCusData, pGeter, &Geter::slot_getCusData, Qt::QueuedConnection);
    
    // C++11 lambda
    connect(pSender, &Sender::sig_sendCusData, [](Data &data){
        // to do
    });

    // 不僅僅QObject
    auto fun = std::function<void(Data)>{
            
    };
    connect(pSender, &Sender::sig_sendCusData, fun);
  • 訊號的過載,使用函式指標轉換即可
  • 自定義資料型別,qRegisterMetaType<T>("Tname")
  • emit 關鍵字沒有非常實用
  • 新語法,它可以連線QObject的任何成員方法,不僅僅是定義的槽。lambda,bind,function
  • 連線型別,預設AutoConnection。連線的型別確定時機:訊號發出。判定規則:接受者所依附的執行緒和傳送者所依附的執行緒是否相同,相同則直連,否則佇列連。槽函式工作的執行緒:直連時,在訊號的傳送端;佇列連時,在接受端。(個人認為:連線型別不應該人為修改,選擇預設的就可以)
(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.

既然使用了qRegisterMetaType,順帶說下Q_DECLARE_METATYPE,這樣就可使用Qt的萬能資料QVariant了,單這個只是在直連時有效,因此配合qRegisterMetaType使用。

Q_DECLARE_METATYPE宣告一個自定義型別時,我們要為該類宣告預設構造,拷貝構造,過載等於號,解構函式。eg:

// Creating Custom Qt Types
class CusVar{
public:
    CusVar(){}
    CusVar(const CusVar &other){info = other.info;}
    ~CusVar(){}

    void operator = (const CusVar &other){
        info = other.info;
    }

    QString getInfo(){return info;}
private:
    QString info = "123";
};
Q_DECLARE_METATYPE(CusVar)
    在QVariant使用中
    
    QVariant varData;
    // default
    CusVar var;
    // copy
    varData.setValue(var);

    // default
    CusVar getVar;
    // copy =
    getVar = varData.value<CusVar>();
    qDebug() << "get cusVar" << getVar.getInfo();

    // copy
    CusVar getVarEx = varData.value<CusVar>();
    qDebug() << "get cusVarEx" << getVarEx.getInfo();