教程三 在Go中使用Energy创建跨平台应用 - 状态控制

news2025/7/29 10:09:13

本文介绍在Energy中如何像浏览器一样控制状态, 页面的加载、前进、后退、刷新、暂停刷新

前提-需要安装好开发环境参考:教程一环境安装

创建应用

  • 开发环境中 MacOSX平台必须在"GlobalCEFInit"之前设置CEF
  • 设置使用CEF 和 CEF框架目录,生成开发执行应用程序包
    • macapp.MacApp.IsCEF(common.IsDarwin())
  • 全局初始化 每个应用都必须调用的
    • cef.GlobalCEFInit(&libs, &resources)
  • 可选的应用配置
    • cfg := cef.NewApplicationConfig()
  • 指定chromium的二进制包框架根目录, 不指定为当前程序执行目录
    • 环境变量ENERGY_HOME="/app/cefframework" 配置框架所在目录

    if common.IsWindows() {
        //SetFrameworkDirPath 或 配置环境变量 ENERGY_HOME
        //cfg.SetFrameworkDirPath("D:\\app.exe\\energy\\chromium64")
    } else if common.IsLinux() {
        //cfg.SetFrameworkDirPath("/home/sxm/app/swt/energy/chromium")
    }

  • 创建应用
    • cef.NewApplication(cfg)
  • 主进程窗口初始化函数
    • src.MainBrowserWindow()

package main

import (
	"embed"
	"github.com/energye/energy/cef"
	"github.com/energye/energy/common"
	"github.com/energye/energy/example/browser-control/src"
	"github.com/energye/golcl/pkgs/macapp"
)

//go:embed resources
var resources embed.FS

//go:embed libs
var libs embed.FS

func main() {
	//开发环境中 MacOSX平台必须在"GlobalCEFInit"之前设置CEF
	//设置使用CEF 和 CEF框架目录,生成开发执行应用程序包
	macapp.MacApp.IsCEF(common.IsDarwin())
	//环境变量 ENERGY_HOME="/app/cefframework" 配置框架所在目录
	//全局初始化 每个应用都必须调用的
	cef.GlobalCEFInit(&libs, &resources)
	//可选的应用配置
	cfg := cef.NewApplicationConfig()
	//指定chromium的二进制包框架根目录,
	//不指定为当前程序执行目录
	if common.IsWindows() {
		//SetFrameworkDirPath 或 配置环境变量 ENERGY_HOME
		//cfg.SetFrameworkDirPath("D:\\app.exe\\energy\\chromium64")
	} else if common.IsLinux() {
		//cfg.SetFrameworkDirPath("/home/sxm/app/swt/energy/chromium")
	}
	//创建应用
	cefApp := cef.NewApplication(cfg)
	//主进程窗口
	src.MainBrowserWindow()

	//运行应用
	cef.Run(cefApp)
}

系统UI和Energy

使用系统组件 golcl 创建控制相关按钮

初始主进程和窗口

  • 在非主进程中有些代码是不必执行的。通过IsMain函数判断是否为主进程
    • commons.Args.IsMain()
  • 使用主浏览器的配置属性对浏览器进行了简单的配置
    • cef.BrowserWindow.Config
  • 使用ChromiumConfig配置开启右键菜单和开发者工具
    • config.SetEnableMenu(true)
    • config.SetEnableDevTools(true)

  • 创建窗口时的回调函数 对浏览器事件设置,和窗口属性组件等创建和修改
  • cef.BrowserWindow.SetBrowserInit 窗口初始函数
  • 在窗口初始函数中
    • 设置更多的窗口属性
    • 窗口的事件
    • 浏览器的事件
  • cef.QueueAsyncCall 函数,在Linux中和操作UI相关的功能中,需要使用该函数包裹住,该函数会将被执行的函数移至主线程中执行。否则操作UI相关或Linux系统中会导致UI线程锁死
  • func controlUI 函数,在SetBrowserInit 函数中调用,主要创建主窗口内的系统UI组件
package src

import (
	"fmt"
	"github.com/energye/energy/cef"
	"github.com/energye/energy/common"
	"github.com/energye/golcl/lcl"
	"github.com/energye/golcl/lcl/types"
)

//主浏览器窗口
func MainBrowserWindow() {
	//只有启动主进程才会继续执行
	if !common.Args.IsMain() {
		return
	}
	//主窗口的配置
	//指定一个URL地址,或本地html文件目录
	cef.BrowserWindow.Config.DefaultUrl = "https://energy.yanghy.cn/"
	//窗口的标题
	cef.BrowserWindow.Config.Title = "Energy - 浏览器控制"
	//窗口宽高
	cef.BrowserWindow.Config.Width = 1024
	cef.BrowserWindow.Config.Height = 768
	//chromium配置
	config := cef.NewChromiumConfig()
	config.SetEnableMenu(true)
	config.SetEnableDevTools(true)
	cef.BrowserWindow.Config.SetChromiumConfig(config)
	//创建窗口时的回调函数 对浏览器事件设置,和窗口属性组件等创建和修改
	cef.BrowserWindow.SetBrowserInit(func(event *cef.BrowserEvent, browserWindow *cef.TCefWindowInfo) {
		//设置应用图标 这里加载的图标是内置到执行程序里的资源文件
		lcl.Application.Icon().LoadFromFSFile("resources/icon.ico")
		//在窗体初始化时创建窗口内的组件
		back, forward, stop, refresh, progressLabel, addr := controlUI(browserWindow)
		//页面加载处理进度
		event.SetOnLoadingProgressChange(func(sender lcl.IObject, browser *cef.ICefBrowser, progress float64) {
			//linux 更新UI组件必须使用 QueueAsyncCall 主线程异步同步
			cef.QueueAsyncCall(func(id int) {
				//参数-进度
				progressLabel.SetCaption(fmt.Sprintf("%v", progress*100))
			})
		})
		//页面加载状态,根据状态判断是否加载完成,和是否可前进后退
		event.SetOnLoadingStateChange(func(sender lcl.IObject, browser *cef.ICefBrowser, isLoading, canGoBack, canGoForward bool) {
			//linux 更新UI组件必须使用 QueueAsyncCall 主线程异步同步
			cef.QueueAsyncCall(func(id int) {
				//控制按钮状态
				stop.SetEnabled(isLoading)
				refresh.SetEnabled(!isLoading)
				back.SetEnabled(canGoBack)
				forward.SetEnabled(canGoForward)
			})
		})
		event.SetOnAddressChange(func(sender lcl.IObject, browser *cef.ICefBrowser, frame *cef.ICefFrame, url string) {
			cef.QueueAsyncCall(func(id int) {
				addr.SetText(url)
			})
		})
	})
	//创建窗口之后对对主窗口的属性、组件或子窗口的创建
	cef.BrowserWindow.SetBrowserInitAfter(func(browserWindow *cef.TCefWindowInfo) {
		fmt.Println("SetBrowserInitAfter")
	})
}

//控制组件UI
//地址栏和控制按钮创建
func controlUI(browserWindow *cef.TCefWindowInfo) (goBack *lcl.TButton, goForward *lcl.TButton, stop *lcl.TButton, refresh *lcl.TButton, progressLabel *lcl.TLabel, addrBox *lcl.TComboBox) {
	window := browserWindow.Window
	//这里使用系统UI组件
	//创建panel做为地址栏的父组件
	addrPanel := lcl.NewPanel(window) //设置父组件
	addrPanel.SetParent(window)
	addrPanel.SetAnchors(types.NewSet(types.AkLeft, types.AkTop, types.AkRight)) //设置锚点定位,让宽高自动根据窗口调整大小
	addrPanel.SetHeight(25)
	addrPanel.SetWidth(window.Width())
	//创建 按钮-后退
	goBack = lcl.NewButton(addrPanel) //设置父组件
	goBack.SetParent(addrPanel)
	goBack.SetCaption("后退")
	goBack.SetBounds(0, 0, 35, 25)
	goForward = lcl.NewButton(addrPanel) //设置父组件
	goForward.SetParent(addrPanel)
	goForward.SetCaption("前进")
	goForward.SetBounds(35, 0, 35, 25)
	stop = lcl.NewButton(addrPanel) //设置父组件
	stop.SetParent(addrPanel)
	stop.SetCaption("停止")
	stop.SetBounds(35+35, 0, 35, 25)
	refresh = lcl.NewButton(addrPanel) //设置父组件
	refresh.SetParent(addrPanel)
	refresh.SetCaption("刷新")
	refresh.SetBounds(35+35+35, 0, 35, 25)

	//创建下拉框
	addrBox = lcl.NewComboBox(addrPanel)
	addrBox.SetParent(addrPanel)
	addrBox.SetLeft(35 + 35 + 35 + 35)                                         //这里是设置左边距 上面按钮的宽度
	addrBox.SetWidth(window.Width() - (35 + 35 + 35 + 35 + 35 + 35))           //宽度 减按钮的宽度
	addrBox.SetAnchors(types.NewSet(types.AkLeft, types.AkTop, types.AkRight)) //设置锚点定位,让宽高自动根据窗口调整大小
	addrBox.Items().Add("https://energy.yanghy.cn")
	addrBox.Items().Add("https://www.baidu.com")

	//显示加载进度
	progressLabel = lcl.NewLabel(addrPanel) //设置父组件
	progressLabel.SetParent(addrPanel)
	progressLabel.SetCaption("0")
	progressLabel.SetBounds(window.Width()-(35+35)-10, 3, 35, 25)
	progressLabel.SetAnchors(types.NewSet(types.AkTop, types.AkRight)) //设置锚点定位,让宽高自动根据窗口调整大小

	goUrl := lcl.NewButton(addrPanel) //设置父组件
	goUrl.SetParent(addrPanel)
	goUrl.SetCaption("GO")
	goUrl.SetBounds(window.Width()-35, 0, 35, 25)
	goUrl.SetAnchors(types.NewSet(types.AkTop, types.AkRight)) //设置锚点定位,让宽高自动根据窗口调整大小

	//重新调整browser窗口的Parent属性
	//重新设置了上边距,宽,高
	window.WindowParent().SetAlign(types.AlNone) //重置对齐,默认是整个客户端
	window.WindowParent().SetTop(25)
	window.WindowParent().SetHeight(window.Height() - 25)
	window.WindowParent().SetWidth(window.Width())
	//设置锚点定位,让宽高自动根据窗口调整大小
	//因为窗口大小已调整,这里不能使用 SetAlign 了
	window.WindowParent().SetAnchors(types.NewSet(types.AkTop, types.AkLeft, types.AkRight, types.AkBottom))

	//给按钮增加事件
	goBack.SetOnClick(func(sender lcl.IObject) {
		browserWindow.Chromium().GoBack()
	})
	goForward.SetOnClick(func(sender lcl.IObject) {
		browserWindow.Chromium().GoForward()
	})
	stop.SetOnClick(func(sender lcl.IObject) {
		browserWindow.Chromium().StopLoad()
	})
	refresh.SetOnClick(func(sender lcl.IObject) {
		browserWindow.Chromium().Reload()
	})
	goUrl.SetOnClick(func(sender lcl.IObject) {
		var url = addrBox.Text()
		if url != "" {
			browserWindow.Chromium().LoadUrl(url)
		}
	})
	return
}

go run xx.go

go build

go build -ldflags “-H windowsgui -s -w”

说明

需要你自己下载编译好的框架二进制包,或使用energy命令行工具安装环境,参考教程CEF和Enregy使用
这里面用到了系统UI组件

  1. 首先创建了应用,应用创建属于不管主进程还是渲染进程(子进程)都要执行的代码, 通过NewApplicationConfig配置应用参数,需要你使用(SetFrameworkDirPath)指定框架目录,如果执行文件在框架目录中,则不需要指定.
  2. 创建主窗口,在CEF中主窗口是主进程,UI的主进程,也是brower的主进程,大多数业务逻辑都要在该进程中实现
  3. 在主进程中创建了窗口组件,按钮控制组件,事件监听,窗口属性设置等等.

控制事件

在回调函数BrowserWindow.SetBrowserInit设置事件监听

cef.BrowserWindow.SetBrowserInit(func(event *cef.BrowserEvent, browserWindow *cef.TCefWindowInfo)

设置加载进度改变事件

event.SetOnLoadingProgressChange(func(sender lcl.IObject, browser *cef.ICefBrowser, progress float64)

设置页面加载状态事件

event.SetOnLoadingStateChange(func(sender lcl.IObject, browser *cef.ICefBrowser, isLoading, canGoBack, canGoForward bool)

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

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

相关文章

【kafka】十、kafka消费者offset维护

消费者offset维护 offset维护 由于consumer在消费过程中可能会出现断电宕机等故障,consumer恢复后,需要从故障前的位置继续消费,所以consumer需要实时记录自己消费到了哪个offset,以便恢复后继续消费。 消费者是按照消费者组来保…

第八章 动态规划 3 AcWing 1554. 找更多硬币

第八章 动态规划 3 AcWing 1554. 找更多硬币 原题链接 AcWing 1554. 找更多硬币 算法标签 DP 背包问题 思路 经典01背包问题 闫氏DP分析法 状态表示 状态初始化 状态计算 状态转移方程式 要求字典序最小,因此先存硬币面额到数组再降序排列,保…

App逆向之frida-dexdump脱壳分析某肿瘤sign

声明:本文仅限学习交流使用,禁止用于非法用途、商业活动等。否则后果自负。如有侵权,请告知删除,谢谢!本教程也没有专门针对某个网站而编写,单纯的技术研究 一、firda 的安装 国内下载很慢:pip…

docker容器网络

第七章容器网络 Docker网络 veth pair:成对出现的一种虚拟网络设备,数据从一端进,从另一端出。用于解决网络命名空间之间隔离。 docker0:网桥是一个二层网络设备,通过网桥可以将Linux支持的不同端口连接起来&…

Git常见命令与使用,从0到1学会使用Git

👨‍💻个人主页: 才疏学浅的木子 🙇‍♂️ 本人也在学习阶段如若发现问题,请告知非常感谢 🙇‍♂️ 📒 本文来自专栏: 常见软件安装与运用 ❤️ 支持我:👍点赞…

linux NPS 服务端安装 +linux 客户端安装

本文参考博客: https://blog.csdn.net/m0_57776598/article/details/123674866 一、下载安装包 1、官方下载 官方下载地址:https://github.com/ehang-io/nps/releases 注意不要下错了,当前我下的版本为 v0.26.10 2、网盘下载 网盘下载&…

Python编程 字典的常用操作

作者简介:一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.字典 1.访问字典(掌握) 2.字典的增加与修改(掌握) 3.系列删除(掌握) …

Web3中文|元宇宙在商业中的最佳应用

来源 | techrepublic 编译 | DaliiNFTnews.com 麻省理工学院斯隆管理学院的信息技术高级讲师Paul McDonagh-Smith说,麻省理工学院的人工智能先驱Marvin Minsky创造了“手提箱式词语”一词——即一些词或术语本身没有任何意义,而需要人去挖掘、赋予和丰…

计算机英文论文写作需要注意哪些细节? - 易智编译EaseEditing

1)尽量用动词少用名词化 那些大篇名词的文章真的很难读懂,而有强大动词的句子更容易理解。 我们注意到客户在论文中经常使用的名词有“agreement”, “disagreement”, “investigation”, “analysis”, “examination”, “comparison”, “increase…

【MySQL技术专题】「索引技术」体验前所未有的技术探险,看穿索引的本质和技术体系(1)

文章目录前提概要数据库类型内容架构索引和磁盘的关系数据读取时主要时间开销总结分析瓶颈点优化的方式数据量计算传统暴力(顺序型读写)X索引机制(半随机性读写)√索引升级之多级索引化(全随机性读写)使用索…

读书笔记《Spring Boot+Vue全栈开发实战》(下)

本书将带你全面了解Spring Boot基础与实践,带领读者一步步进入 Spring Boot 的世界。前言第九章 Spring Boot缓存第十章 Spring Boot安全管理第十一章 Spring Boot整合WebSocket第十二章 消息服务第十三章 企业开发第十四章 应用监控第十五章 项目构建与部署第十六章…

【python与数据分析】Pandas统计分析基础

目录 前言 一、pandas常用数据类型 综述 1.一维数组(Series)与常用操作 (1) 通过列表创建Series (2)创建Series时指定索引 (3)Series位置和标签的使用 (4&#x…

m基于中继协助的认知无线电频谱切换机制的matlab仿真分析

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 认知无线电网络在进行频谱切换的时候,最为重要的问题是如何以最少的频谱切换次数实现频谱切换,同时保证较好的服务质量,这里,服务质量不仅…

植入“人工心脏”助患者重获“心”生

【同期】人工心脏移植患者 刘女士这要是在过去的时候也就放弃了,我再活20年,我还能看着我大孙子成家,这就是我最大的希望。【解说】11月22日,人工心脏移植患者和心脏移植患者在即将康复出院前,互相握手庆贺。据了解&am…

【UDS】ISO14229之0x3E服务

文章目录前言一、理论描述二、使用步骤1.请求2.响应总结->返回总目录<- 前言 简称&#xff1a; “TesterPresent”&#xff0c;测试工具保持连接服务 功能&#xff1a; 此服务用于告知电控单元测试工具仍在线。该服务需周期性发送&#xff0c;用于重置 S3server 计时器…

SQL语句练习

1. 创建学生表 S(命名格式“姓名拼音_三位学号_s”&#xff0c;如 LBJ_023_s)并插入数据 2. 创建课程表 C(命名格式“姓名拼音_三位学号_c”&#xff0c;如 LBJ_023_c) 并插入数据 3. 创建选课表 SC(命名格式“姓名拼音_三位学号_sc”&#xff0c;如 LBJ_023_sc) 并插入数据 …

寻找链表相交结点问题

寻找链表相交结点问题 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;寻找链表相交结点问题 CSDN&#xff1a;寻找链表相交结点问题 题目描述 给定两个可能有环也可能无环的单链表&#xff0c;头节点head1和head2。请实现一个函数&#xff0c;如果两个链表…

Vue3路由守卫、vuex的使用、vuex模块化拆分、vite中自动导入模块文件

文章目录1. 路由守卫2. vuex的使用2.1 基本使用2.2 模块化拆分方式一方式二方式三3. 在vite中自动导入模块文件1. 路由守卫 vue3 中的导航守卫与 vue2 中的基本一致&#xff0c;不同的地方在于&#xff0c;vue3 中导航守卫取消了 next 参数&#xff0c;而是通过返回 false 来取…

【Silvaco example】GaN diode, Reverse-bias leakage current vs temperature

1、例子讲解 该示例演示了&#xff0c;GaN肖特基二极管中&#xff0c;因声子辅助隧穿&#xff08; phonon-assisted tunneling &#xff09;的反向偏置漏电流的温度依赖性建模。 例子参考以下论文&#xff1a; Pipinys P., and V. Lapeika, "Temperature dependence of …

Android入门第36天-以一个小动画说一下Android里的Handler的使用

简介 我们在前面的Android教程中已经提到过这么一件事&#xff1a;Android在启动后会有一个主线程。它不允许任何子线程去改变主UI线程里的内容。 这么做是为了妨止&#xff0c;万一有一个带有大事务的线程导致了渲染组件时间过长最终导致Android UI出现“闪退”、“崩溃”的…