我們已經介紹了qt的signal和slot,現在該講講它的struct tags系統了。qt擁有多種的struct tags,我們會去一一瞭解它們。
什麼是struct tags?
struct tag
又叫做結構體標籤,顧名思義,它就是用來給結構體欄位做標記的。比如我們熟悉的JSON就使用了tags:
type User struct { UserId int `json:"user_id" bson:"user_id"` UserName string `json:"user_name" bson:"user_name"`}
tags由反引號包裹,name在:
之前,value在:
之後由雙引號包裹。
有了這些tags,我們的代碼就可以很輕鬆的使用reflect來取得tags的name和name對應的值:
u := &User{UserId: 1, UserName: "tony"}t := reflect.TypeOf(u)field := t.Elem().Field(0)fmt.Println(field.Tag.Get("json")) // "user_id"fmt.Println(field.Tag.Get("bson")) // "user_id"
我們的qt正是依賴這一特性實現了Qt的moc系統,使用不同的tags除了可以實現signal和slot之外還能實現moc的多種功能,甚至是qt自己的一些擴充。
“->” 和 “<-”
在signal裡我們已經介紹了auto,它具有很多的局限性,項目作者也表示auto應該盡量單獨使用,不應該使用auto(...)
的形式。而為了更方便的串連signal和slot,我們就需要用到->
和<-
了。
先看個樣本,這次我們從官方的例子裡節選一段:
type Chart struct { core.QObject *charts.QChart _ func() `constructor:"init"` _ func() `slot:"handleTimeout,<-(this.m_timer.timeout)"`}
對於槽handleTimeout,我們使用了<-
,它和下面這句等價:
this.m_timer.ConnectTimeout(this.handleTimeout)
意思是將this.m_timer
的Timeout訊號和this.handleTimeout
函數connect,當觸發了this.m_timer
的Timeout訊號時這個函數也會被調用。
你也可以不指定訊號名稱,預設會和signal tag指定的訊號名同名的函數進行connect:
_ func() `slot:"handleTimeout,<-(this.m_timer)"`
和
_ func() `slot:"handleTimeout,<-(this.m_timer.handleTimeout)"`
等價。
我們再來看一下->
的使用:
import "controller"type dialogTemplate struct { core.QObject _ func() `constructor:"init"` _ func(cident string) `signal:"show,<-(controller.Controller)"` _ func(bool) `signal:"blur,->(controller.Controller)"`}
可以看到,我們對訊號Blur使用了->
,這個表達的含義與<-
相反,它是將signal tag聲明的訊號或是slot tag聲明的槽與->
之後的函數進行connect,當你觸發這個訊號或是調用這個槽時,括弧內的函數也會被調用,等價於:
this.ConnectBlur(controller.Controller.blur)
或是(如上面所說,可以省略函數名)
this.ConnectBlur(controller.Controller)
“->”和“<-”的一些使用規則
上一段裡我們已經提到可以在這兩個tags裡省略串連和被連線物件的函數名,這裡還有幾個規則:
- 括弧裡指定的可以是全域對象,包括匯入的包裡的可見對象,例如上個例子裡的
controller.Controller
。
- this代指當前對象的執行個體(可以理解為c++的
this
,python的self
預留位置,或者golang的receiver
)。
- 括弧裡的內容還可以是
this.StructField
,也就是對象裡的欄位
- 對於想串連繼承的
QObject
及其衍生類別或是其他類的signal/slot,目前只能使用this.BaseClass.method
的形式(與auto類似),這一點作者表示會在以後改進。
“->”和“<-”以及“auto”
這三者都需要和signal/slot tag配合使用,他們都會自動connect訊號和槽,但是它們也有許多不同。
- 首先我們日常使用應該盡量使用
singal:"signalName,auto"
而不是auto(...)
,->
或<-
,如果只是為了少寫Connect*
,那麼不應使用後三者,因為除非你有大量的Connect*
需要編寫,否則容易影響代碼閱讀,特別是對連線物件是當前類執行個體的成員函數時。
->
和<-
用於不同的對象之間進行互動,比起分散的Connect*
調用,在struct tags裡聲明邏輯關係更易於維護。
->
和<-
用於串連已有的訊號和槽,如果想複用基類或者成員變數的signal和slot,你就需要->
或<-
替代auto
。
- 和QML互動時,也應該使用
->
和<-
串連來自QML的signals。
客觀上這三者都能極大的簡化我們對signal/slot的實現和使用,所以根據不同的情境需求,我們需要選用合適的tags來簡化我們的開發。
下一篇文章我們將瞭解constructor
這個tag,qt中的建構函式。
如果對本篇有什麼疑問或者建議,歡迎在評論中提出。
祝玩得愉快!