时间过得很快,一转眼,离上次发文章,又好久过去了,最近又忙着公司的项目,很久没学习Go的windows开发了。趁着双休日,再来稍微玩下。
上次,我们成功的创建了第一个窗口程序,当时,默认的创建了一个edit类型的窗口,所以,该窗口自己就是一个edit的窗口。今天,不打算这样做了,得来点正常的了,就是创建一个原始的窗口,啥都不是,就是一个窗口,然后,再在这个窗口里面创建一个子窗口,子窗口有很多种,今天就用Button(按钮)窗口。开始动手吧~~
一、创建原始窗口
关键代码:
对比上次创建的窗口,我们发现第102行,与上次不太一样,上次是_TEXT("edit"),这次换成了_TEXT("test"),没错。上次的是创建一个edit的窗口,而这次是自定义的原始窗口,你应该已经猜到了这次的窗口我们取名叫test。
既然,有了test,那么test这里只是个字符串名称呀,所以,我们得先注册这个窗口对象。如何注册,我们把注册过程封装成了一个方法。
2 func RegisterClass(){
3 var wndProcPtr uintptr = syscall.NewCallback(WndProc)
4 hInst := GetModuleHandle(nil)
5 if hInst == 0 {
6 panic("GetModuleHandle")
7 }
8 hIcon := LoadIcon(0, (*uint16)(unsafe.Pointer(uintptr(IDI_APPLICATION))))
9 if hIcon == 0 {
10 panic("LoadIcon")
11 }
12 hCursor := LoadCursor(0, (*uint16)(unsafe.Pointer(uintptr(IDC_ARROW))))
13 if hCursor == 0 {
14 panic("LoadCursor")
15 }
16 var wc WNDCLASSEX
17 wc.CbSize = uint32(unsafe.Sizeof(wc))
18 wc.LpfnWndProc = wndProcPtr
19 wc.HInstance = hInst
20 wc.HIcon = hIcon
21 wc.HCursor = hCursor
22 wc.HbrBackground = COLOR_BTNFACE + 1
23 wc.LpszClassName = syscall.StringToUTF16Ptr("test")
24 if atom := RegisterClassEx(&wc); atom == 0 {
25 panic("RegisterClassEx")
26 }
27 }
第一行,我们把消息处理过程方法,转换成了一个指针,在 18行赋值给WNDCLASSEX结构体。其余的都是一些初始化操作,例如初始化鼠标,背景,窗体大小等等。还有在第23行是不是看到了test,我们给注册的这个窗口名字叫test,这样在之前那个创建窗口的代码片段中就能成功调用这个test了。其它参数具体参加win32 api。
最后,在main方法中调用这个注册窗体方法。
二、创建子窗体
创建子窗体其实和创建窗体一个样,没什么特别,只不过将它的实例句柄指向父窗口。这里我们要创建一个按钮,为了方便起见,也稍微封装下,添加个添加按钮的方法:
注意看21行,这里是button,明白了吧?和你想的一样,确实这么简单,你要创建什么窗体就指定什么。另外注意第28行,parent,是的,指定该窗体的父窗体。该变量通过方法参数传来,是一个HWND类型的变量。那么,我们该在何时使用该方法添加按钮呢?继续往下看。。。。。。
三、添加按钮
何时添加按钮,一般的做法就是当父窗体创建的时候就添加,这里就需要用到WM_CREATE消息了,我们在消息处理方法中,监听该消息,然后如果接受到该消息,就执行addButton方法,添加按钮到父窗体中。
细心的同学可能会发现,这次的消息处理方法的最后和上次不太一样,是的,这次最后调用了DefWindowProc函数,该函数调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理。该函数确保每一个消息得到处理。
最后运行结果如下:
今天就到这里,下次将为按钮添加事件处理。。。。。。