通过walk开发windows界面

准备工作 #

go get github.com/akavel/rsrc
go get github.com/lxn/win
go get github.com/lxn/walk

简单示例 #

package main

import (
	"log"

	"github.com/lxn/win"

	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

type MyWindow struct {
	*walk.MainWindow
	hWnd        win.HWND
	ni          *walk.NotifyIcon
}

func (mw *MyWindow) removeStyle(style int32) {
	currStyle := win.GetWindowLong(mw.hWnd, win.GWL_STYLE)
	win.SetWindowLong(mw.hWnd, win.GWL_STYLE, currStyle&style)
}

func (mw *MyWindow)GetIcon()walk.Image  {
	icon, err := walk.Resources.Image("img/check.ico")
	if err != nil {
		log.Fatal(err)
	}
	return icon
}


func (mw *MyWindow) AddNotifyIcon() {
	var err error
	mw.ni, err = walk.NewNotifyIcon(mw)
	if err != nil {
		log.Fatal(err)
	}

	_ = mw.ni.SetIcon(mw.GetIcon())
	_ = mw.ni.SetVisible(true)


	mw.ni.MouseDown().Attach(func(x, y int, button walk.MouseButton) {
		if button == walk.LeftButton {
			mw.Show()
			win.ShowWindow(mw.Handle(), win.SW_RESTORE)
		}
	})

}

//使用declarative实现
func (mw *MyWindow)NewMainWindowEx(title string)  {
	if err := (MainWindow{
		AssignTo: &mw.MainWindow ,
		Title:    title,
		Size:     Size{550, 380},
		Layout:   VBox{MarginsZero: true},
		Children: []Widget{

		},
	}.Create()); err != nil {
		log.Fatal(err)
	}
}


//使用walk和win实现
func (mw *MyWindow)NewMainWindowEx1(title string)  {
	mw.MainWindow,_ = walk.NewMainWindow()
	_ = mw.SetLayout(walk.NewVBoxLayout())
	_ = mw.SetSize(walk.Size{Height: 380, Width: 550})
	_ = mw.SetTitle(title)
	_ = mw.SetX((int(win.GetSystemMetrics(0)) - mw.Width()) / 2)
	_ = mw.SetY((int(win.GetSystemMetrics(1)) - mw.Height()) / 2)
	mw.Show()
	win.ShowWindow(mw.Handle(), win.SW_RESTORE)
}

//主程序
func main() {
	mw := new(MyWindow)
	mw.NewMainWindowEx1("托盘小程序")
	mw.hWnd = mw.Handle()
	_ = mw.SetIcon(mw.GetIcon())
	mw.removeStyle(^win.WS_SIZEBOX)
	mw.removeStyle(^win.WS_MAXIMIZEBOX)
	mw.AddNotifyIcon()
	mw.Run()
}




清单文件 main.manifest #

main.manifest应用程序配置元数据清单文件

  • main.manifest 保存在 main.go同级目录下

  • 直接复制 “文件内容” 即可,没特殊情况不用修改

  • 解决win7/win8/win10应用程序兼容问题

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
	<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="SomeFunkyNameHere" type="win32"/>
	<dependency>
		<dependentAssembly>
			<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
		</dependentAssembly>
	</dependency>
	<asmv3:application>
		<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
			<dpiAware>true</dpiAware>
		</asmv3:windowsSettings>
	</asmv3:application>
</assembly>

具体关于manifest的介绍和使用

https://blog.csdn.net/hellokittymeng/article/details/75574780

生成 / 编译: #


第一步:将 main.manifest 生成为 main.syso #

  • 这个步骤只需要运行一次, 调试/编译 只需一直执行 第二步
  • 生成的 main.syso可以拿到别的 GUI 项目中使用的
  • 除非你想修改 main.manifest 或者 图标文件 才要重新生成一次
  • 在当前窗口下 打开 cmd,运行如下命令:
rsrc -manifest main.manifest -o main.syso

第二步:编译成独立的 exe 文件 #

  • 不管 调试 还是 正式编译,都必须通过 双击 exe 文件运行,无法使用 go run main.go 直接运行
  • 调试:
go build
  • 正式编译:
go build -ldflags="-H windowsgui -w -s"

窗口

托盘

包提供示例在项目外部库的地址

github.com\lxn\walk@v0.0.0-20210112085537-c389da54e794\examples