Qt 深入了解信號槽

2018-10-04 10:06 更新

深入了解信號槽

信號槽機(jī)制是 Qt 編程的基礎(chǔ)。通過信號槽,能夠使 Qt 各組件在不知道對方的情形下能夠相互通訊。這就將類之間的關(guān)系做了最大程度的解耦。

槽函數(shù)和普通的 C++ 成員函數(shù)沒有很大的區(qū)別。它們也可以使 virtual 的;可以被重寫;可以使public、protected 或者 private 的;可以由其它的 C++ 函數(shù)調(diào)用;參數(shù)可以是任何類型的。如果要說區(qū)別,那就是,槽函數(shù)可以和一個信號相連接,當(dāng)這個信號發(fā)生時,它可以被自動調(diào)用。

connect()語句的原型類似于:

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

這里,sender 和 receiver 都是 QObject 類型的,singal 和 slot 都是沒有參數(shù)名稱的函數(shù)簽名。SINGAL()和SLOT()宏用于把參數(shù)轉(zhuǎn)換成字符串。

深入的說,信號槽還有更多可能的用法,如下所示。

一個信號可以和多個槽相連:

connect(slider, SIGNAL(valueChanged(int)),
              spinBox, SLOT(setValue(int))); 
connect(slider, SIGNAL(valueChanged(int)),
              this, SLOT(updateStatusBarIndicator(int)));

注意,如果是這種情況,這些槽會一個接一個的被調(diào)用,但是它們的調(diào)用順序是不確定的。

多個信號可以連接到一個槽:

connect(lcd, SIGNAL(overflow()),
              this, SLOT(handleMathError())); 
connect(calculator, SIGNAL(divisionByZero()),
              this, SLOT(handleMathError()));

這是說,只要任意一個信號發(fā)出,這個槽就會被調(diào)用。

一個信號可以連接到另外的一個信號:

connect(lineEdit, SIGNAL(textChanged(const QString &)),
              this, SIGNAL(updateRecord(const QString &)));

這是說,當(dāng)?shù)谝粋€信號發(fā)出時,第二個信號被發(fā)出。除此之外,這種信號-信號的形式和信號-槽的形式?jīng)]有什么區(qū)別。

槽可以被取消鏈接:

disconnect(lcd, SIGNAL(overflow()),
                 this, SLOT(handleMathError()));

這種情況并不經(jīng)常出現(xiàn),因為當(dāng)一個對象 delete 之后,Qt 自動取消所有連接到這個對象上面的槽。

為了正確的連接信號槽,信號和槽的參數(shù)個數(shù)、類型以及出現(xiàn)的順序都必須相同,例如:

connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
              this, SLOT(processReply(int, const QString &)));

這里有一種例外情況,如果信號的參數(shù)多于槽的參數(shù),那么這個參數(shù)之后的那些參數(shù)都會被忽略掉,例如:

connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), 
            this, SLOT(checkErrorCode(int)));

這里,const QString &這個參數(shù)就會被槽忽略掉。

如果信號槽的參數(shù)不相容,或者是信號或槽有一個不存在,或者在信號槽的連接中出現(xiàn)了參數(shù)名字,在Debug 模式下編譯的時候,Qt 都會很智能的給出警告。

在這之前,我們僅僅在 widgets 中使用到了信號槽,但是,注意到 connect()函數(shù)其實是在 QObject 中實現(xiàn)的,并不局限于 GUI,因此,只要我們繼承 QObject 類,就可以使用信號槽機(jī)制了:

class Employee : public QObject 
{ 
        Q_OBJECT 
public: 
        Employee() { mySalary = 0; }  
        int salary() const { return mySalary; } 

public slots: 
        void setSalary(int newSalary); 

signals: 
        void salaryChanged(int newSalary); 

private: 
        int mySalary; 
};

在使用時,我們給出下面的代碼:

void Employee::setSalary(int newSalary) 
{ 
        if (newSalary != mySalary) { 
                mySalary = newSalary; 
                emit salaryChanged(mySalary); 
        } 
}

這樣,當(dāng) setSalary()調(diào)用的時候,就會發(fā)出 salaryChanged()信號。注意這里的 if 判斷,這是避免遞歸的方式!還記得前面提到的循環(huán)連接嗎?如果沒有 if,當(dāng)出現(xiàn)了循環(huán)連接的時候就會產(chǎn)生無限遞歸。

本文出自 “豆子空間” 博客,請務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/194031

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號