上一篇文章里我們詳細介紹了signal的用法。
今天我們將介紹slot的使用。在qt中slot和signal十分相像,這次我們將實現一個能顯示16進制數字的SpinBox,它繼承自QSpinbox並重寫了validate
,valurFromText
和textFromValue
這三個slot,以便能將原先的10進制整數值顯示為16進制。我們將在其中展示slot的具體用法。
slot的聲明
我們先看一下示例:
type HexSpinbox struct {
widgets.QSpinBox
_ func() `constructor:"init"`
_ func(int) string `slot:"textFromValue,auto"`
_ func(string) int `slot:"valueFromText,auto"`
_ func(string, int) gui.QValidator__State `slot:"validate,auto"`
validator *gui.QRegExpValidator
}
我們看到和signal一樣,需要用struct tags來指定slot和它的名字,名字一樣會被strings.Title
處理。在Qt中slot實質上是普通的函數,所以是允許擁有返回值的。
我們同樣看到slot也可以指定auto
,沒錯對於slot,qt也會像signal一樣生成Connect[slot name]
,Disconnect[slot name]
和[slot name]
這三個函數。
這里有一點需要特別注意,在qt中生成slot函數其實和信號一樣,是一個空殼函數,需要用Connect[slot name]
使其和具體的函數連接,這樣才可以通過[slot name]
函數使用這個slot。而auto
則和signal會自動進行connect。
到目前為止,我們的slot其實和普通的成員函數沒什么區別,而且在qt中signal可以和任意函數連接,那么為什么還要特意聲明成slot呢?
那是因為我們要對slot進行重寫,對Qt熟悉的讀者可能已經發現我們的例子里的三個slot正是QSpinBox的slot,我們對它們進行了重寫。因為使用了moc系統,直接使用struct里的同名函數進行重寫是無效的,所以我們需要用到slot tags。而我們例子里類的派生類也可以通過slot tags來重寫基類的slots。如此一來自定義組件將會更為方便和靈活。
slot的使用
前面提到過,想要使用slot,得先connect它,這是和Qt的重要區別之一:
// init 初始化對象,由NewHexSpinBox自動調用
func (h *HexSpinbox) init() {
h.SetRange(0, 255)
// 我們通過正則來驗證輸入,保證只能輸入16進制數字
regexp := core.NewQRegExp2("[0-9A-Fa-f]{1,8}", core.Qt__CaseSensitive, core.QRegExp__RegExp)
h.validator = gui.NewQRegExpValidator2(regexp, h)
}
// slots 的實現,這些slot都由spinbox自動調用
// validate 對輸入進行驗證,無法通過的內容不會被顯示
func (h *HexSpinbox) validate(input string, pos int) gui.QValidator__State {
return h.validator.Validate(input, pos)
}
// textFromValue 將輸入或增加/減少后的內容轉換成string並顯示出來
func (h *HexSpinbox) textFromValue(value int) string {
return strconv.FormatInt(int64(value), 16)
}
// valueFromText 將顯示或輸入的合法內容轉換成整數int
func (h *HexSpinbox) valueFromText(text string) int {
value, _ := strconv.Atoi(text)
return int(value)
}
// NewHexSpinbox是moc生成的構造函數,我們以后會講解
box := NewHexSpinbox(nil)
// 連接slot,使其可用,如果指定了auto就無需手動connect,這里作為示例進行演示
box.ConnectValidate(box.validate)
box.ConnectTextFromValue(box.textFromValue)
box.ConnectValueFromText(box.valueFromText)
連接好之后我們就能調用box.Validate
,box.ValueFromText
和box.TextFromValue
啦。
// 就像signal,調用他們時連接的函數也會被調用
// 一點區別在於slot擁有返回值,所以你也可以使用變量來接收slot返回的結果
box.ValueFromText("ff") // -> 255
box.TextFromValue("26") // -> "1a"
當然,我們重寫這些slot不是為了在代碼里調用的,而是為了改變SpinBox顯示行為的。
下面是main函數,對於slot的處理完成之后,像使用普通的widget一樣使用我們的HexSpinBox即可:
func main() {
widgets.NewQApplication(len(os.Args), os.Args)
hexSpin := NewHexSpinbox(nil)
hexSpin.Show()
widgets.QApplication_Exec()
}
顯示效果:
怎么樣,是不是很簡單? qt就是這樣一個簡單而又靈活的庫,后面我們還將進行跟深入的研究。如果有意見和建議歡迎在評論中指出,也歡迎大家積極提出問題。
祝玩得愉快!