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

news2024/9/20 5:26:04

项目采用的是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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【突发】国内大量家用路由器网络访问异常和流量劫持事件分析

以下内容由WebRAY和Panabit联合发布 0x01 事件背景 从2024年5月开始,国内部分家用路由器开始出现间歇性断网、域名解析延迟高以及解析到海外IP等情况,今年8月该现象变得尤为严重。前几天在做应急响应时候发现某企业暴露在公网上的路由器配置的DNS地址被莫…

无线自组网应急指挥系统解决方案详解

随着全球自然灾害频发和社会应急事件的增加,如地震、洪水、泥石流等,传统的通信手段在面对这些极端情况时往往显得力不从心。尤其是在灾区,基础设施的损毁往往导致通信网络瘫痪,使得救援行动陷入困境。如何在这种紧急情况下迅速建…

深度学习入门(六):无监督学习

一、K-means算法 K-means算法是一种常用的聚类算法,旨在将数据集划分成 k 个簇,使得每个簇中的数据点尽可能相似,而不同簇之间的数据点差异尽可能大。该算法是基于迭代的方法来寻找最优的簇中心,并通过不断调整簇的划分来最小化簇…

【web安全】权限漏洞之未授权访问

一.Jenkins未授权访问漏洞 步骤一:使用以下fofa语法进行搜索 port"8080" && app"JENKINS" && title"Dashboard [Jenkins]" 步骤二:进入执行页面http://xxx.xxx.xxx.xxx:xxxx/manage/script/index.php 执…

预训练大语言模型综述来了!中国人民大学教授发表包含了416个参考文献的大语言模型综述

尽管大语言模型在最近今年发展十分迅速,但是相关的综述却相对比较落后。本文是由中国人民大学教授Wayne Xin Zhao等人前几天刚公开的关于大语言模型的综述,论文正文部分共32页,包含了416个参考文献。内容十分详实。 这份大模型综述我已经打包…

【iOS多线程(三)】优先级反转问题

优先级反转 实时操作系统的一个基本要求就是基于优先级的抢占系统。保证优先级高的线程在“第一时间”抢到执行权,是实时系统的第一黄金准则。 但是这种基于优先级抢占的系统,有一个著名的问题需要关注,就是“优先级反转”(Prio…

优思学院:标准化作业在精益管理之屋中的位置

除了两大支柱,我们必须要对整个精益之屋进行理解,才可以知道精益生产的全貌。精益之屋由4部分组成:地基、2个支柱和屋顶。 首先,地基就是5S活动、目视化管理、标准化作业来建立稳定性。 而标准化作业正正是大家都忽略&#xff0…

计算机网络408考研 2020

2020 湖科大教书匠的个人空间-湖科大教书匠个人主页-哔哩哔哩视频 计算机网络408考研 历年真题解析(有字幕无背景音乐版)_哔哩哔哩_bilibili 计算机网络408考研2020年真题解析_哔哩哔哩_bilibili 1 2 3 41 11 1

cmake 编译教程

一、只有一个源文件的程序编译 首先在当前目录下创建两个文件 hello.cpp CMakeLists.txt (注意CMakeLists大小写,不要写错了) cmake_minimum_required (VERSION 2.8)project (learn_cmake)add_executable(hello hello.cpp) 第一行意思是…

基于R语言绘制GGE双标图4

参考资料: https://cran.r-project.org/web/packages/GGEBiplots/GGEBiplots.pdf 1、数据整理 使用GGEBiplots包绘制双标图,分析用数据是二维数据表(行表示品种或基因型,列表示试验点或环境)。当我们的数据表是一维数…

ip地址是公网还是内网?内网电脑ip地址在哪看

在数字化时代,IP地址作为网络设备的唯一标识符,扮演着至关重要的角色。然而,你是否知道IP地址是内网还是外网?对于内网电脑,我们又该如何快速准确地找到其IP地址呢?下面带着这些疑问跟着虎观代理小二一起深…

《python语言程序设计》2018版第6章第37题,随机生成字符,使用RandomCharacter生成100个小写字母,每行15个

一、正常输出方法设计的代码结构 老规矩用正常输出法设计代码结构 def getRandomCharacter(ch1, ch2):return chr(random.randint(ord(ch1), ord(ch2)))def getRandomLowerCaseLetter():return getRandomCharacter(a, z)count 0 for i in range(100):count 1a getRandomLowe…

深度学习实战(1):树叶分类pytorch

Classify Leaves | Kaggle 上面是数据集 数据导入与数据处理 %matplotlib inline import torch from torch.utils import data as Data import torchvision from torch import nn import torchvision.models as models from IPython import display import os import pandas…

leetcode69. x 的平方根,二分法

leetcode69. x 的平方根 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0…

培训第二十三天(mysql主从脚本与mysql详细语句介绍)

上午 在同步时,对删除和修改都比较慎重(监控同步时) mysql主从搭建 前提软件libaio,rsync 1、主2、从3、同步4、测试 注意:先执行从服务器的脚本,再执行主服务器脚本 master-mysql配置脚本 先要在主服务…

企元数智小程序合规分销系统赠送:迎接数字化时代商机

当今时代,随着科技的高速发展和数字化的普及,企业如何抓住数字化时代带来的商机,成为了业界关注的焦点。在这样一个竞争激烈的市场环境下,企业需要不断提高自身的竞争力和应变能力,以应对激烈的市场竞争,开…

Phpstorm实现本地SSH开发远程机器(或虚拟机)项目

适用场景: 1、windows系统想要运行仅支持linux、mac系统的项目,可将项目运行在本地虚拟机,但是在虚拟机里使用vim编辑很麻烦,如何实现在本地用Phpstorm来编辑虚拟机中的代码? 下面的说明都是以本地虚拟机为例&#xff…

java之拼图小游戏(开源)

public class LoginJFrame extends JFrame {//表示登录界面,以后所有跟登录相关的都写在这里public LoginJFrame() {//设置界面的长和宽this.setSize(603,680);//设置界面的标题this.setTitle("拼图登陆界面");//设置界面置顶this.setAlwaysOnTop(true);/…

科研绘图系列:R语言圆形条形图(circular barplot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 介绍 圆形条形图(circular barplot)是一种条形图,其中的条形沿着圆形而不是线性排列展示。这种图表的输入数据集与普通条形图相同:每个组(一个组即一个条形)需要一个数值。(更多解释请参…

linux文件查找--locate和find命令详解

在文件系统上查找符合条件的文件 文件查找:1.非实时查找(数据库查找):locate2.实时查找: find应用:生产环境中查找到系统中占用磁盘空间较大且时间比较久的大日志文件,对这个较大的日志文件做处理(删除移走等),防止它占用更多的磁…