目前来说,用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(因为我写的小工具仅用到了这几个控件)。之后支持的控件会慢慢变多。
下一篇会讲到如何自定义控件,先秀一下近期正在做的小软件的界面,还远远没有完工,但我自己挺满意的。呵呵