在上週老師說了項目需要學習qt後,就去找了個qt的教程,看了看,教程一上來就開始介紹qt的信號與槽,說這是qt中一個很重要的東西,然後就下一步了……,後面的代碼中也沒有特別感受到這個的強大與獨特(應該是對編程的理解還不夠深的原因),就上網找了找技術博客看,發現大部分文章都對菜鳥不太友好,不過最終還是讓我找到了一篇讓新手也能透徹明白的文章 ,這裏記錄一下自己的收穫。
信號與槽
先讓我們看看它的定義:
聽着很強,很高級。
簡單的用途就是
當一個特定的事件發生時,一個或幾個被指定的信號就被髮射,槽就是一個返回值爲void的函數,如果存在一個或幾個槽和該信號相連接,那在該信號被髮射後,這個(些)槽(函數)就會立刻被執行
理解倒是不難,不就是觸發了一個函數嗎?完全感受不到作爲一個框架的核心特性的強大。
信號與槽的作用
要感受它的強大還是得從它的作用中體會(也許教程中的老師也是這麼想的,只是我沒體會到……)。
在圖形界面編程中,很多時候我們希望一個可視對象發生某種變化時通知另一個或幾個對象,再一個地說,我們希望任 何一類的對象能和其他對象進行通訊。例如,某個數值顯示窗口負責顯示某個滾動條對象的當前數值,當滾動條對象的值發生變化時,我們希望數值顯示窗口能收到 來自滾動條對象發送的“數值改變”的信號,從而改變自己的顯示數值。
這些在其他圖形框架中可以用回調實現,不過,相比於回調函數,信號和槽機制是類型安全的(沒搞太懂爲什麼安全),一個信號的簽名必須與它的接收槽的簽名相匹配,這樣編譯器就可以幫助我們檢查類型是否匹配。信號和槽是很寬鬆的聯繫在一 起的,一個發射信號的對象不用考慮哪個槽會接收這個信號,接收信號的槽的所在對象也不知道要連接的信號是哪個對象發射的。QT的信號和槽機制可以保證如果 你把一個信號和一個槽連接起來後,槽會在正確的時間使用信號的參數而被調用,信號和槽可以使用任何數量、類型的參數。
換一種說法,在使用信號與槽時你得先連接一下他們。下面是信號與槽的代碼實現
使用信號和槽的QT對象:
class UseSignalClass {
Q_OBJECT
public:
UseSignalClass (void) {}
int value (void) const {return _value;}
public slots:
int setValue (int value) {_value = value;} // 定義槽
signals:
void valueChanged (int);
private:
int _value;
}
void UseSignalClass::setValue( int value )
{
if ( value != _value ) {
_val = value;
emit valueChanged(value);
}
}
emit valueChanged(value);這行代碼是發射一個信號valueChanged。
要想使一個槽在一個信號被髮射後被執行,要顯示地進行連接:
UseSignalClass a,b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
然後當a改變時,b也會跟着變,而b的改變不會影響到a,因爲b不會給a發信號。
注意
下面是信號與槽的使用中的一些注意事項:
1、信號和槽的機制是非常有效的,但是它不像“真正的”回調那樣快。信號和槽稍微有些慢,這是因爲它們所提供的靈活性。但這種損失相對來說是比較小的。但要追求高效率的話,比如在實時系統中就要儘量少用這種機制。
2、信號和槽機制與普通函數的調用一樣,如果使用不當的話,在程序執行時有可能形成死循環,所以,在定義槽函數時一定要注意避免間接形成無限循環,即在槽中再次發射所接收到的同樣的信號。
3、如果一個信號和多個槽相關聯的話,那當這個信號被髮射時,與之相關聯的槽的執行順序將是髓機的,且順序不能指定。
4、宏定義不能用在signal和slot的參數中。
5、構造函數不能用在signals和slots聲明區域內。
6、函數指針不能作爲信號或槽的參數。
7、信號和槽不能有缺省參數值。
8、信號和槽不能攜帶模板類參數。
9、嵌套的類不能位於信號和槽區域內,也不能有信號或者槽。
10、友元聲明不能位於信號和槽的聲明區域內。
總結
學習是一個一步一步的過程,學的時候千萬不要太着急,應該剋制自己總想直接搞最後一步的想法,畢竟那樣學習曲線會太過陡峭,容易讓人失去信心,就像這次要不是知道回調,在看相關博客時,肯定也是看的雲裏霧裏的。