目錄
前言:
信號和槽初識
兩個問題
前言:
本文我們正式開始介紹信號與槽這個概念,在談及Qt中的信號與槽這個概念之前,我們不妨回顧一下Linux中的信號,比如發生了除0錯誤,OS就會給該進程發送一個信號,使該進程終止。
那么Linux中涉及信號的時候,涉及到了誰發出的,什么信號,執行的行為,誰接受的。在我們前文熟悉Qt的整個框架的時候,使用的函數connect,參數分別就是上面涉及到了四個點,所以實際上Qt中的信號和Linux中的信號是有很多相同點的,那么有了Linux的基礎,在這里學習Qt我們就要輕松很多了。
信號和槽初識
說到底,我們現在還是沒有理解什么是槽,什么是信號,這里先給一個結論:
信號和槽都是函數
但是,為什么信號是函數這里并不打算展開來說,我們在這里能理解的是槽是函數,那么也就是說,某個控件接收到了某個信號,就要執行對應的槽函數,那么我們為什么控件知道接收到了某個信號就應該執行某個槽函數呢?
這是因為connect將槽函數和信號關聯在了一起。
那么槽和信號的觸發順序是什么呢?我們不妨舉個女朋友在一個月中總有那么不舒服的幾天,當我們接收到了女朋友不舒服的這個信號,我們就應該知道我們該倒紅糖水,該揉揉肚子什么的。
所以對于信號和槽的一個處理順序來看,我們就應該知道,在信號處理之前,我們一定要有槽函數的這個定義,如果沒有定義,我們就錯過了這個信號的處理,自然而言的,女朋友的”蜀道難“也就來了。
那么我們回到Qt就知道,connect函數實際上是一個回調函數,信號是函數吧?槽是函數吧?那么這兩個函數作為了connect函數的參數,也就成就了一個典型回調函數。
那么既然介紹到了connect,對于參數部分我們就不用提及了,對于C++中的庫函數我們都是知道來源于誰的,那么connect函數是來源于誰呢?
牽扯到了這個問題,我們就不得不談一談Qt中的一個繼承關系,拿隔壁java舉例,我們知道java的所有類都繼承于一個專門的類,叫做Object,在Qt中也有一個類似的設定,即QObject是所有內置類的祖宗:
那么connect函數呢就是QObject中的一個靜態成員函數。
//connect to a functor, with a "context" object defining in which event loop is going to be executedtemplate <typename Func1, typename Func2>static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,Qt::ConnectionType type = Qt::AutoConnection)
這是它的一個函數定義。
對于我們之前看到的connect函數好像又有所不同,我們之前使用的connect函數好像沒有那么復雜,我們之前使用Qt函數的原型是:
可是你看上面的類型,好像無論如何都沒有辦法和char*打上交道,對于第一個和第三個來說多正常,因為這兩個參數是接收控件的嘛,子類賦值給基類,非常正常,可是其他參數呢?
之前使用第二個和第四個的參數可是函數指針類型,和char*是一點沒有關系的,這怎么能夠防在一起?實際上兩個宏有關,一個是給槽函數傳參的時候要搭配一個SLOT宏,一個是給信號函數傳參的時候需要搭配一個SIGNAL宏。這兩個宏可以讓傳入的指針變成char*。所以以前寫的時候,是這樣使用connect函數的:
connect(button,SIGNAL(&QPushButton::clicked),this,SLOT(&Widget::close));
但是這個寫法是Qt4之前的了,對于新版的Qt就不用這樣寫了,實在是麻煩,新版的Qt5支持了一個重載版本,使得第二個和第四個參數變成了泛型指針,我們也就不用宏了,當然你要想那樣寫應該也沒事兒~
這個時候的Qt就有了一個類型檢查的功能,在上文提供的一個源碼來說:
const typename QtPrivate::FunctionPointer<Func1>::Object *sender
這是一個類型萃取器,如果傳入的參數第一個和第二個不匹配,第三個和第四個不匹配,主要指的是函數指針,編譯就會報錯了~當然,這里我們了解一下就行。
現在我們來了解一下信號,我們會發現之前使用button的信號的時候,有兩個click,一個是過去分詞形式,一個是動詞形式:
其中這個鋸齒形狀的就是slot函數,也就是槽函數,比如我觸發了一個信號,然后某個按鈕就click了,對于波紋狀的就是信號函數,是我們點擊了,然后觸發了信號。
這是二者的區別。
對于connect函數來說,第一個和第二個的參數類型應該是匹配的,第一個比如是button,第二個就應該是父類的信號,不能是其他的,比如QLineEdit的。
以上是對connect函數的一個簡單理解。
實際上在以前老版本的時候,實現槽函數應該在前面加:
?
public slot:void Handle();
但是現在不用了~你要想也可以~?
如何查閱
我咋知道QPushButton中有個clicked信號?我咋知道QWidget有個close槽?
也就是我們可以延展到我們怎么翻閱文檔?
直接就是打開一手assistant,從中我們直接在索引部分找QPushButtion,但是我們似乎翻遍了文檔也沒有找到clicked信號。
這其實是因為clicked是繼承于它的父類的,那么我們從哪里進到父類呢?
Inherits是繼承,也就是說該類是繼承于QAbstractButton的,下面的同理,我們點進去看看:
就可以看到它同樣是繼承了別的類的。
往下滑動就可以看到對應的槽函數和信號函數了,那么信號函數的缺省值我們不用管,稍微想想也能相通。
以上是對信號和槽的一個簡單知識輸出。
感謝閱讀!