当第一次看到go程序在windows平台生成可执行的exe文件,就宣告了windows应用也一定是go语言的战场。go不是脚本语言,但却有着脚本语言的轻便简单的特性。相较于php和python之类以服务器控制台为主要战场的脚本语言来说,go语言是真正的圆了“动态语言的应用开发梦”。
windows桌面应用依赖于win api,画出各种应用界面和控件本质上就是调用windows提供的api。go开发windows app要做的第一件事情就是封装这些windows api。
<a href="https://github.com/lxn/go-winapi">https://github.com/lxn/go-winapi</a>
这个项目已经实现了对winapi的封装。比如你会在go-winapi/user32.go中找到createwindowex的封装:

这里是使用了syscall包。这里要说明一下,golang的官方文档没有对syscall.syscall12的说明,需要查看代码,这里的syscall12代表了createwindowex传入的参数有12个,已经实现的syscall方法还有
syscall, syscall6, syscall9, syscall12, syscall15。
下一步,有基本的winapi之后,需要的是各个控件的使用接口。官方并没有提供标准库,但是有许多开源项目已经完成了这个封装,下面就是几个开源项目:
这里推荐和使用的是lxn的walk项目(windows application library kit),walk封装的控件应该是这几个里面最全的了,并且也在不断的完善中。
比如bitmap, radiobutton, checkbox, pushbutton等。在walk/example中能看到几个例子提供参考
好了,有了go-winapi和walk两个开源项目,就可以开始做一个windows app了
界面如下:
这个是一个简易的socket im, 在一台机子上开启两个端口,8000和8001,两个端口相互监听和发送消息。
go版本的socket im 源码:
<a href="https://github.com/jianfengye/myworks/tree/master/go_socketim">https://github.com/jianfengye/myworks/tree/master/go_socketim</a>
实现总是简单的,说几个代码片段:
1 walk.initialize(walk.initparams{paniconerror: true})
2 defer walk.shutdown()
3
4 mainwnd, err := walk.newmainwindow()
5 if err != nil {
6 return
7 }
8
9 mw := &mainwindow{mainwindow: mainwnd}
10
11 mw.setsize(walk.size{120, 150})
12 mw.show()
13 mw.run()
button1, _ := walk.newpushbutton(mw)
button1.settext("start port 8000")
button1.setx(10)
button1.sety(10)
button1.setwidth(100)
button1.setheight(30)
button1.clicked().attach(func() {
go newtalkwindow(mw, 8000, 8001)
button1.setenabled(false)
})
创建ui基本就靠这两步就行了,当然walk还有更为复杂的控件使用方法,这里没有使用。
func (this *talkwindow)send() error {
txt := this.sendtext.text()
conn, err := net.dial("tcp", "localhost:" + strconv.itoa(this.sendport))
if err != nil {
return err
}
lenth := len([]byte(txt))
pre := int32tostream(int32(lenth),bigendian)
fmt.fprintf(conn, string(pre) + txt)
this.sendtext.settext("")
return nil
}
func (this *talkwindow)listen() error {
ln, err := net.listen("tcp", ":" + strconv.itoa(this.listenport))
for {
conn, err := ln.accept()
if err != nil {
continue
}
go func(){
buffer := make([]byte, 4)
conn.read(buffer)
lenth := streamtoint32(buffer, bigendian)
contentbuf := make([]byte, lenth)
conn.read(contentbuf)
text := strings.trimspace(string(contentbuf))
fmt.println(text)
this.showtext.settext(this.showtext.text() + time.now().format("2006-01-02 10:13:40") + breakchars + strconv.itoa(this.sendport) + ":" + text + "\r\n")
}()
}
ui创建完成后就是具体的业务逻辑了,这里的业务逻辑比较简单,主要使用了net包建立和监听tcp端口。
使用go相较于c#获益更多的是在逻辑实现方面,比如在c#中开启多进程,一个进程监听消息一个进程收取消息,这样的实现是比较麻烦和繁琐的,需要使用thread库。但是在go中是使用goroutine实现的,直接开一个goroutine来监听消息,主进程发送消息,很符合思维逻辑的编程方式。
go相较于c#不足的应该说是ide方面了,go还没有能可视化编程应用ide。但是walk库使用熟练了,我想这应该不是问题,而且也有理由相信在不久会出现类似的ide。
go在将来有没有可能支持移动终端应用的开发呢?android,ios?据说能使用go开发android应用的要求已经提上议程了,毕竟都是google的孩子嘛。至于ios可能还有很长的路要走。
ps: 截止至2012/11/6,walk的更新版本已经把 walk.initialize去掉了,换成其他函数了,故本文中的例子请做相应修改
具体可以看这个comment