用 GO 开发一个windows桌面图形化软件入门

项目采用的是walk技术方案

一、初始化项目

创建一个文件夹比如demo,然后进入demo执行

复制代码
go mod init demo

二、安装walk模块

复制代码
go get github.com/lxn/walk
go get github.com/lxn/win

三、安装rsrc

安装:

复制代码
go install github.com/akavel/rsrc

生成*.syso文件

复制代码
rsrc -manifest main.manifest -o rsrc.syso

四、编写代码

main.go

复制代码
var logger *log.Logger
var mainWindow *walk.MainWindow
var isLogin bool

func init() {
	logger = service.CreateLogService()
	isLogin = service.CheckLoginStatus(logger)
}
func main() {
	ui.CreateGUI(logger, mainWindow, isLogin)
}

ui

复制代码
var loginGUIWidth, loginGUIHeight int

func init() {
	loginGUIWidth = 400
	loginGUIHeight = 100
}

func CreateGUI(logger *log.Logger, mw *walk.MainWindow, isLogin bool) {
	if !isLogin {
		LoginGUI(logger, mw)
	} else {
		MainGUI(logger)
	}
}

func LoginGUI(logger *log.Logger, mw *walk.MainWindow) {
	var username, password *walk.LineEdit
	mw, err := walk.NewMainWindow()
	if err != nil {
		panic(err)
		logger.Fatalln("LoginUI create error")
		return
	}
	MainWindow{
		AssignTo: &mw,
		Title:    "登录",
		Size:     Size{Width: loginGUIWidth, Height: loginGUIHeight},
		Layout:   VBox{},
		Children: []Widget{
			Composite{
				Layout: Grid{Columns: 2},
				Children: []Widget{
					Label{
						Text: "                            用户名:",
					},
					LineEdit{
						AssignTo: &username,
						MaxSize:  Size{Width: 150, Height: 40},
					},
				},
			},
			Composite{
				Layout: Grid{Columns: 2},
				Children: []Widget{
					Label{
						Text: "                            密    码:",
					},
					LineEdit{
						AssignTo:     &password,
						MaxSize:      Size{Width: 150, Height: 40},
						PasswordMode: true,
					},
				},
			},
			Composite{
				Layout: HBox{},
				Children: []Widget{
					PushButton{
						Text:    "登录",
						MaxSize: Size{Width: 50, Height: 40},
						OnClicked: func() {
							flag := service.LoginService(username.Text(), password.Text())
							if flag {
								service.SaveLoginStatus(logger)
								mw.Close()
								MainGUI(logger)
							} else {
								walk.MsgBox(mw, "错误", "用户名或密码错误", walk.MsgBoxIconError)
							}
						},
					},
				},
			},
		},
	}.Create()
	setWindowMaxDisable(mw)
	setWindowSizeDisable(mw)
	setWindowIcon(logger, mw)
	setOriginLocation(mw, loginGUIWidth, loginGUIHeight)
	setSysTray(logger, mw)
	// setSysNotification(logger, mw, "syscloud", "正在连接中")
}

// 禁用窗口最大化
func setWindowMaxDisable(mw *walk.MainWindow) {
	hwnd := mw.Handle()
	currStyle := win.GetWindowLong(hwnd, win.GWL_STYLE)
	win.SetWindowLong(hwnd, win.GWL_STYLE, currStyle&^win.WS_MAXIMIZEBOX)
}

// 禁用窗口大小修改
func setWindowSizeDisable(mw *walk.MainWindow) {
	hwnd := mw.Handle()
	currStyle := win.GetWindowLong(hwnd, win.GWL_STYLE)
	win.SetWindowLong(hwnd, win.GWL_STYLE, currStyle&^win.WS_SIZEBOX)
}

func MainGUI(logger *log.Logger) {
	mw, err := walk.NewMainWindow()
	MainWindow{
		AssignTo: &mw,
		Title:    "主窗口",
		Size:     Size{Width: loginGUIWidth, Height: loginGUIHeight},
		Layout:   VBox{},
		Children: []Widget{
			Composite{
				Layout: Grid{Columns: 2},
				Children: []Widget{
					Label{
						Text: "                        主窗口信息:",
					},
					LineEdit{
						MaxSize:  Size{Width: 150, Height: 40},
						Text:     "这是主窗口",
						ReadOnly: true,
					},
				},
			},
		},
	}.Create()
	if err != nil {
		walk.MsgBox(mw, "错误", "程序打开失败", walk.MsgBoxIconError)
		walk.App().Exit(0)
		return
	}
	// mw.SetVisible(true)
	setSysTray(logger, mw)
	// setSysNotification(logger, mw, "syscloud", "正在连接中")
}

// 设置窗口初始位置
func setOriginLocation(mw *walk.MainWindow, width int, height int) {
	mw.SetX(int(win.GetSystemMetrics(win.SM_CXSCREEN))/2 - width/2)
	mw.SetY(int(win.GetSystemMetrics(win.SM_CYSCREEN))/2 - height/2)
}

// 设置icon
func setWindowIcon(logger *log.Logger, mw *walk.MainWindow) {
	icon := getIcon(logger)
	mw.SetIcon(icon)
}

// 获取icon
func getIcon(logger *log.Logger) walk.Image {
	icon, err := walk.Resources.Image("resource/icon.ico")
	if err != nil {
		logger.Println("ERROR:获取icon失败", err)
	}
	return icon
}

// 设置系统托盘
func setSysTray(logger *log.Logger, mw *walk.MainWindow) {
	notifyIcon, err := walk.NewNotifyIcon(mw)
	if nil != err {
		logger.Println("ERROR:设置提醒图标失败")
	}
	defer notifyIcon.Dispose()
	icon := getIcon(logger)
	err = notifyIcon.SetIcon(icon)
	if nil != err {
		logger.Println("ERROR:设置图标失败")
	}
	notifyIcon.SetVisible(true)
	if err := notifyIcon.SetToolTip("syscloud客户端"); err != nil { // 设置系统托盘悬浮信息
		logger.Println("ERROR:设置悬浮信息失败", err)
	}
	setConnectMenu(logger, notifyIcon)
	setDisconnectMenu(logger, notifyIcon)
	setExitMenu(logger, notifyIcon)
	notifyIcon.ShowInfo("syscloud", "正在连接中")
	// notifyIcon.ShowInfo("syscloud", "连接成功")
	mw.Run()
}

// 系统托盘右键菜单(退出)
func setExitMenu(logger *log.Logger, ni *walk.NotifyIcon) {
	exitAction := walk.NewAction()
	if err := exitAction.SetText("退出"); err != nil {
		logger.Println(err)
	}
	//Exit 实现的功能
	exitAction.Triggered().Attach(func() { walk.App().Exit(0) })
	if err := ni.ContextMenu().Actions().Add(exitAction); err != nil {
		logger.Println(err)
	}
}

// 系统托盘右键菜单(连接)
func setConnectMenu(logger *log.Logger, ni *walk.NotifyIcon) {
	connectAction := walk.NewAction()
	if err := connectAction.SetText("连接"); err != nil {
		logger.Println(err)
	}
	connectAction.Triggered().Attach(func() {
		// 连接功能
		service.ConnectService(logger)
	})
	if err := ni.ContextMenu().Actions().Add(connectAction); err != nil {
		logger.Println(err)
	}
}

// 系统托盘右键菜单(断开)
func setDisconnectMenu(logger *log.Logger, ni *walk.NotifyIcon) {
	disconnectAction := walk.NewAction()
	if err := disconnectAction.SetText("断开"); err != nil {
		logger.Println(err)
	}
	disconnectAction.Triggered().Attach(func() {
		// 断开功能
		service.DisconnectService(logger)
	})
	if err := ni.ContextMenu().Actions().Add(disconnectAction); err != nil {
		logger.Println(err)
	}
}

五、界面效果

登录

主界面

更多代码:

imcc2022/clientDemo: 一个用walk框架写的windowsGUI示例(golang)/A windows GUI demo written by walk framework(golang) (github.com)

相关推荐
码行山野赴时序归途5 分钟前
顺序表(Sequential List)详解:从数组到 C 语言实现
c语言·开发语言·数据结构·算法
扬大平仔8 分钟前
# 小深:用 AgentScope Java 2.0 Harness 做私人助手(上)mysql
java·开发语言·mysql
java porter10 分钟前
我开源了一个 Spring AI Agent 项目
后端
阿里云基础软件18 分钟前
一句话看透 JVM,SysOM 诊断 Skill 新增 Java 应用诊断能力
java·开发语言·jvm·人工智能·操作系统·sysom 诊断 skill
ctlover33 分钟前
Python高级与正则表达式
开发语言·python
1360967572334 分钟前
AgentScope 2.0 学习笔记:RAG 进阶——Top-K 调优与幻觉测试(让 Agent 敢说「不知道」)
后端
泡海椒35 分钟前
生产环境安全配置:JQuickJavaInvocationGuard自定义防护规则实战
开发语言·python·安全
yume_sibai41 分钟前
07-Rust 异步编程完全指南(async/await + Tokio + Future + 并发原语 + 异步流)
开发语言·后端·rust
linx2951 小时前
单元七 · 零基础路线图-第 1–3 周·变量、类型与字符串
c语言·开发语言·数据结构·c++·算法
2601_953988071 小时前
Ricon组态 - 让数据可视化如此简单
运维·后端·物联网·数学建模·前端框架·c4前端