今天我們來講講自定義組件和它的構造函數。 在前面的文章里我們已經接觸了好幾個自定組件,這次的示例是一個自定義對話框,他有一個about按鈕,點擊按鈕可以顯示出Qt的信息或者用戶輸入的信息。這是效果圖: 下麵我們就來重點講解自定義組件和它的構造函數吧。 構造函數的聲明 先上代碼: type MyDia ...
今天我們來講講自定義組件和它的構造函數。
在前面的文章里我們已經接觸了好幾個自定組件,這次的示例是一個自定義對話框,他有一個about按鈕,點擊按鈕可以顯示出Qt的信息或者用戶輸入的信息。這是效果圖:
下麵我們就來重點講解自定義組件和它的構造函數吧。
構造函數的聲明
先上代碼:
type MyDialog struct {
widgets.QDialog
_ func() `constructor:"init"`
_ func(string) `signal:"showAbout"`
_ func() `signal:"showAboutQt"`
_ func(bool) `slot:"aboutClicked,auto"`
_ func(string) `slot:"enableAboutButton,auto"`
label *widgets.QLabel
edit *widgets.QLineEdit
testCheck *widgets.QCheckBox
isDialogCheck *widgets.QCheckBox
aboutButton *widgets.QPushButton
closeButton *widgets.QPushButton
}
構造函數用 “ _ func() `constructor:"init"` ”
來聲明,目前只支持無參數的構造函數,以後會逐步擴展。之後我們需要實現一個名字是init
的類方法,這是構造函數的實體。
qt的moc系統遇到派生自QObject及其派生類的類時,會自動生成一個New[type name]
的函數(type name也會被Title處理),它會返回一個已經初始化的指向自定義類型實例的指針,這個函數的參數類型會根據最先繼承的QObject或是其派生類的New[type name]
而定,舉個例子:
假設我們的類繼承自QLineEdit
,在qt里有NewQLineEdit(parent QWidget_ITF)
,那麼我們這個類自動生成的New[type name]
就會是New[type name](parent QWidget_ITF)
;
再舉個例子,我們的組件繼承自QWidget,它有NewQWidget(parent QWidget_ITF, fo core.Qt__WindowType)
,那麼我們的類會自動生成New[type name](parent QWidget_ITF, fo core.Qt__WindowType)
。
我們實現的init會被New[type name]
自動調用。不過這裡有個問題,如果我想實現自己的New[type name]
函數呢,比如需要加上自己的配置參數,其實也很簡單,我們再定義一個New[type name]WithXXX
然後在其中調用New[type name]
即可,向下麵這樣:
func NewYourTypeWithConfig(conf Config) *YourType {
// 假設繼承自QWidget
obj := NewYourType(nil, 0)
// 一些額外的初始化處理
// 一般在init里進行界面的初始化,如果你的界面初始化依賴外部數據,那麼可以不指定constructor,
// 這樣New[type name]就不會自動調用init,你可以在自定義函數里調用它。
obj.conf = conf
// obj.init()
}
這就是構造函數的全貌了,接著我們來看看界面的初始化,也就是我們要實現的init函數:
func (d *MyDialog) init() {
d.label = widgets.NewQLabel2("About &Text:", d, 0)
d.edit = widgets.NewQLineEdit(nil)
// 將label和edit綁定
d.label.SetBuddy(d.edit)
d.testCheck = widgets.NewQCheckBox2("Test case", nil)
// 選擇顯示自定義組件的About還是Qt的About
d.isDialogCheck = widgets.NewQCheckBox2("Show &Dialog's about", nil)
// 當用戶輸入要顯示的內容時才可以點擊
d.aboutButton = widgets.NewQPushButton2("&About", nil)
d.aboutButton.SetDefault(true)
d.aboutButton.SetEnabled(false)
d.closeButton = widgets.NewQPushButton2("&Close", nil)
d.closeButton.ConnectClicked( func(_ bool) {
d.Done(0)
})
d.edit.ConnectTextChanged(d.EnableAboutButton)
d.aboutButton.ConnectClicked(d.aboutClicked)
topLeftLayout := widgets.NewQHBoxLayout()
topLeftLayout.AddWidget(d.label, 0, 0)
topLeftLayout.AddWidget(d.edit, 0, 0)
leftLayout := widgets.NewQVBoxLayout()
leftLayout.AddLayout(topLeftLayout, 0)
leftLayout.AddWidget(d.testCheck, 0, 0)
leftLayout.AddWidget(d.isDialogCheck, 0, 0)
rightLayout := widgets.NewQVBoxLayout()
rightLayout.AddWidget(d.aboutButton, 0, 0)
rightLayout.AddWidget(d.closeButton, 0, 0)
rightLayout.AddStretch(0)
mainLayout := widgets.NewQHBoxLayout()
mainLayout.AddLayout(leftLayout, 0)
mainLayout.AddLayout(rightLayout, 0)
d.SetLayout(mainLayout)
d.SetWindowTitle("about")
}
代碼也很簡單,初始化widgets之後使用QBoxLayout
進行佈局,然後連接一下closeButton
,使用QDialog::done
退出dialog。
我們設置aboutButton
初始為不可點擊狀態,直到有輸入內容存在在改變它的狀態,這一步由自動連接的enableAboutButton
槽來完成;
然後是點擊aboutButton
時會檢查isDialogCheck
的值來確定彈出哪種對話框,這一步由aboutClicked
槽來完成:
func (d *MyDialog) aboutClicked(_ bool) {
text := d.edit.Text()
if d.isDialogCheck.IsChecked() {
d.ShowAbout(text)
} else {
d.ShowAboutQt()
}
}
func (d *MyDialog) enableAboutButton(text string) {
if text != "" {
d.aboutButton.SetEnabled(true)
} else {
d.aboutButton.SetEnabled(false)
}
}
然後就是主函數,將顯示About對話框的信號和相應的處理函數連接,然後顯示我們的組件:
func main() {
app := widgets.NewQApplication(len(os.Args), os.Args)
dialog := NewMyDialog(nil, 0)
// 顯示About Qt
dialog.ConnectShowAboutQt( func() {
app.AboutQtDefault()
})
// 顯示自定義內容的About
dialog.ConnectShowAbout( func(text string) {
widgets.NewQMessageBox(dialog).About(dialog, "About Dialog", text)
})
dialog.Show()
app.Exec()
}
顯示About Qt時的效果:
怎麼樣,是不是很簡單,下一篇文章里我們將結束對qt struct tags的探索,如果有任何疑問或者建議,歡迎在評論指出!
祝玩得愉快!