目前來說,用Go寫Windows應用還沒有非常成熟的設計器,習慣了C#那種強大的IDE,再過來看會覺得一朝回到解放前。而且gform現在的設計思路需要使用者對win32 api非常熟悉,否則用起來會非常難受。 這也是我一直在想改善方案的地方,畢竟一個類庫要以好用為目標,只是我充滿了OO思想的頭腦還沒有完全適應Go的設計方式,很多以前信手拈來的思路用到Go上就會出現問題,或者就算套上去了也會覺得與語言格格不入。最明顯就是在努力了兩周之后,我突然發現竟然在模擬類的繼承,天!當時就感覺真的需要停下來了,否則按照現在的慣性做出來的東西肯定一塌糊塗。
關於gform這個框架我的思考還在繼續進行,在弄清楚到底怎樣才是Go的設計模式之后,我相信會對它進行一次大的重構。
好了,現在進入正題,用窗體設計器做界面。原理是還是MFC的老方法,在資源文件中做好對話框設計,然后在運行時attach上去。
打開ResEdit,添加一個對話框,然后在上面放好各種控件。下圖中是一個我做的小工具的實際例子。
其中,為每個控件都設置一個有意義的ID。比如,上圖中“過濾”右邊的文本框,ID為“IDC_FILTER”。
保存之后會發現,ResEdit自動生成了一個與資源文件同名的頭文件,如下所示。
打開這個頭文件,發現里面其實只是簡單的定義了控件ID的值,如下所示。
我們現在新建一個go文件,叫做app.go,把頭文件中的常量定義全都復制進來,變成Go的常量定義,比如:
const (
IDD_DIALOG1 = 104
IDC_CLOSE= 1006
)
可以看到,對話框的ID是IDD_DIALOG1,好,我們現在可以用gform.NewDialogFromResId來把這個對話框讀取出來。
func main() {
gform.Init()
mainform := gform.NewDialogFromResId(nil, IDD_DIALOG1)
mainform.Show()
gform.RunMainLoop()
}
運行一下看看,怎么樣?看到窗體了吧。現在來試試相應按鈕的事件,使用gform.AttachPushButton,之后相應OnLBUp(On Left Button Up即當鼠標左鍵彈起時)。
btnClose = gform.AttachPushButton(mainform, IDC_CLOSE)
btnClose.OnLBUp().Attach(btnClose_OnLBUp)
func btnClose_OnLBUp(arg *gform.EventArg) {
//事件響應代碼寫在這里
}
gform中的事件響應函數很想C#中的委托,每個事件都可以Attach多個事件處理函數,事件激發是會單線程依次調用。而事件響應函數只有一個參數,讓我們來看看gform.EventArg的定義。
type EventArg struct {
sender Controller
data interface{}
}
sender顧名思義,代表激發事件的控件。data里面附帶的就是事件信息,比如,鼠標按鍵事件,data就是MouseEventData類型,定義如下。
type MouseEventData struct {
X, Y int
Button int
Wheel int
}
其他的事件都有自己的事件數據,這里就不一一例舉了。Go的interface{}挺好用的,加上它的靜態類型檢查,很安全、高效。
這樣就完成了,目前gform支持Label、Button、Combobox、Edit、ListView、ProgressBar(因為我寫的小工具僅用到了這幾個控件)。之后支持的控件會慢慢變多。
下一篇會講到如何自定義控件,先秀一下近期正在做的小軟件的界面,還遠遠沒有完工,但我自己挺滿意的。呵呵