升级golcl,增加control示例,增加ipc emit目标接口实现

This commit is contained in:
杨红岩 2022-10-24 22:52:08 +08:00
parent 14ff1e5503
commit 043ef00d14
18 changed files with 298 additions and 47 deletions

View File

@ -382,6 +382,9 @@ func (m *BaseWindow) registerDefaultEvent() {
return false
})
m.chromium.SetOnFrameCreated(func(sender lcl.IObject, browser *ICefBrowser, frame *ICefFrame) {
QueueAsyncCall(func(id int) {
BrowserWindow.putBrowserFrame(browser, frame)
})
if bwEvent.onFrameCreated != nil {
bwEvent.onFrameCreated(sender, browser, frame)
}

View File

@ -33,6 +33,17 @@ type FrameNames struct {
Value string
}
func (m *ICefBrowser) GetBrowserId() int32 {
return m.browseId
}
func (m *ICefBrowser) GetFrameId() int64 {
if mainFrame := m.MainFrame(); mainFrame != nil {
return mainFrame.Id
}
return 0
}
func (m *ICefBrowser) Free() {
m.browseId = 0
}

View File

@ -23,9 +23,9 @@ type IChromiumProc interface {
lcl.IObject
On(name string, eventCallback ipc.EventCallback)
ExecuteJavaScript(code, scriptURL string, startLine int32) //单纯的执行js没有返回值
Emit(eventName string, args ipc.IArgumentList, target *GoEmitTarget) ProcessMessageError
EmitAndCallback(eventName string, args ipc.IArgumentList, target *GoEmitTarget, callback ipc.IPCCallback) ProcessMessageError
EmitAndReturn(eventName string, args ipc.IArgumentList, target *GoEmitTarget) (ipc.IIPCContext, ProcessMessageError)
Emit(eventName string, args ipc.IArgumentList, target IEmitTarget) ProcessMessageError
EmitAndCallback(eventName string, args ipc.IArgumentList, target IEmitTarget, callback ipc.IPCCallback) ProcessMessageError
EmitAndReturn(eventName string, args ipc.IArgumentList, target IEmitTarget) (ipc.IIPCContext, ProcessMessageError)
SetDefaultURL(defaultURL string)
SetEnableMultiBrowserMode(enableMultiBrowserMode bool)
LoadUrl(url string)

View File

@ -111,8 +111,8 @@ func (m *TCEFChromium) ExecuteJavaScript(code, scriptURL string, startLine int32
// 触发JS监听的事件-异步执行
//
// GoEmitTarget 接收目标, nil = mainBrowser mainFrame
func (m *TCEFChromium) Emit(eventName string, args ipc.IArgumentList, target *GoEmitTarget) ProcessMessageError {
// EmitTarget 接收目标, nil = mainBrowser mainFrame
func (m *TCEFChromium) Emit(eventName string, args ipc.IArgumentList, target IEmitTarget) ProcessMessageError {
if eventName == "" {
return PMErr_NAME_IS_NULL
}
@ -126,12 +126,12 @@ func (m *TCEFChromium) Emit(eventName string, args ipc.IArgumentList, target *Go
args = ipc.NewArgumentList()
}
if target == nil {
browser := m.Browser()
browseId = browser.Identifier()
frameId = browser.MainFrame().Id
bsr := m.Browser()
browseId = bsr.Identifier()
frameId = bsr.MainFrame().Id
} else {
browseId = target.BrowseId
frameId = target.FrameId
browseId = target.GetBrowserId()
frameId = target.GetFrameId()
if m.GetBrowserById(browseId).GetFrameById(frameId) == nil {
return PMErr_NOT_FOUND_FRAME
}
@ -146,8 +146,8 @@ func (m *TCEFChromium) Emit(eventName string, args ipc.IArgumentList, target *Go
// 触发JS监听的事件-异步执行-带回调
//
// GoEmitTarget 接收目标, nil = mainBrowser mainFrame
func (m *TCEFChromium) EmitAndCallback(eventName string, args ipc.IArgumentList, target *GoEmitTarget, callback ipc.IPCCallback) ProcessMessageError {
// EmitTarget 接收目标, nil = mainBrowser mainFrame
func (m *TCEFChromium) EmitAndCallback(eventName string, args ipc.IArgumentList, target IEmitTarget, callback ipc.IPCCallback) ProcessMessageError {
if eventName == "" {
return PMErr_NAME_IS_NULL
}
@ -163,12 +163,12 @@ func (m *TCEFChromium) EmitAndCallback(eventName string, args ipc.IArgumentList,
args = ipc.NewArgumentList()
}
if target == nil {
browser := m.Browser()
browseId = browser.Identifier()
frameId = browser.MainFrame().Id
bsr := m.Browser()
browseId = bsr.Identifier()
frameId = bsr.MainFrame().Id
} else {
browseId = target.BrowseId
frameId = target.FrameId
browseId = target.GetBrowserId()
frameId = target.GetFrameId()
if m.GetBrowserById(browseId).GetFrameById(frameId) == nil {
return PMErr_NOT_FOUND_FRAME
}
@ -185,8 +185,8 @@ func (m *TCEFChromium) EmitAndCallback(eventName string, args ipc.IArgumentList,
//
// 使用不当会造成 UI线程 锁死
//
// GoEmitTarget 接收目标, nil = mainBrowser mainFrame
func (m *TCEFChromium) EmitAndReturn(eventName string, args ipc.IArgumentList, target *GoEmitTarget) (ipc.IIPCContext, ProcessMessageError) {
// EmitTarget 接收目标, nil = mainBrowser mainFrame
func (m *TCEFChromium) EmitAndReturn(eventName string, args ipc.IArgumentList, target IEmitTarget) (ipc.IIPCContext, ProcessMessageError) {
if eventName == "" {
return nil, PMErr_NAME_IS_NULL
}
@ -202,12 +202,12 @@ func (m *TCEFChromium) EmitAndReturn(eventName string, args ipc.IArgumentList, t
args = ipc.NewArgumentList()
}
if target == nil {
browser := m.Browser()
browseId = browser.Identifier()
frameId = browser.MainFrame().Id
bsr := m.Browser()
browseId = bsr.Identifier()
frameId = bsr.MainFrame().Id
} else {
browseId = target.BrowseId
frameId = target.FrameId
browseId = target.GetBrowserId()
frameId = target.GetFrameId()
if m.GetBrowserById(browseId).GetFrameById(frameId) == nil {
return nil, PMErr_NOT_FOUND_FRAME
}

View File

@ -28,12 +28,6 @@ type cefV8Context struct {
Global uintptr
}
//GoEmit相关事件的接收目标
type GoEmitTarget struct {
BrowseId int32
FrameId int64
}
//Type ICefCookie
type ICefCookie struct {
Url, Name, Value, Domain, Path string

20
cef/cef-ipc-emit.go Normal file
View File

@ -0,0 +1,20 @@
package cef
type IEmitTarget interface {
GetBrowserId() int32
GetFrameId() int64
}
//GoEmit相关事件的接收目标
type EmitTarget struct {
BrowseId int32
FrameId int64
}
func (m *EmitTarget) GetBrowserId() int32 {
return m.BrowseId
}
func (m *EmitTarget) GetFrameId() int64 {
return m.FrameId
}

View File

@ -15,12 +15,14 @@ import (
"github.com/energye/golcl/lcl/types"
)
type TCEFFrame map[int64]*ICefFrame
// 窗口信息
type TCefWindowInfo struct {
Window *BaseWindow `json:"-"` //窗口Form
Browser *ICefBrowser `json:"-"` //浏览器对象,加载完chromium之后创建
WindowProperty *WindowProperty `json:"-"` //窗口属性
Frames map[int64]*ICefFrame `json:"-"` //当前浏览器下的frame
Frames TCEFFrame `json:"-"` //当前浏览器下的所有frame
auxTools *auxTools //辅助工具
}
@ -259,3 +261,12 @@ func (m *browser) removeNoValidFrames() {
}
}
}
func (m TCEFFrame) GetByFrameId(frameId int64) *ICefFrame {
if m != nil {
if frame, ok := m[frameId]; ok {
return frame
}
}
return nil
}

View File

@ -13,18 +13,19 @@ func sysoRsrc() {
err := syso()
if err != nil {
fmt.Println("syso-error:", err.Error())
//syso失败的时候使用rsrc方式生成该方式需要rsrc.exe执行文件
rsrc()
}
}
func rsrc() error {
rsrc := winRes.NewRSRC()
rsrc.RSRCPath = "E:\\SWT\\gopath\\src\\gitee.com\\snxamdf\\golcl\\exe"
rsrc.CMDDir = "E:\\SWT\\gopath\\src\\swt-lazarus\\demo17-dll-load\\demo-golang-dll-01-chromium"
rsrc.CMDDir = "E:\\SWT\\gopath\\src\\github.com\\energye\\energy\\example\\browser-control"
return rsrc.Gen()
}
func syso() error {
syso := winRes.NewSYSO()
syso.CMDDir = "E:\\SWT\\gopath\\src\\swt-lazarus\\demo17-dll-load\\demo-golang-dll-01-chromium"
syso.CMDDir = "E:\\SWT\\gopath\\src\\github.com\\energye\\energy\\example\\browser-control"
syso.IconName = "icon.ico"
return syso.RC()
}

View File

@ -0,0 +1,37 @@
package main
import (
"embed"
"github.com/energye/energy/cef"
"github.com/energye/energy/commons"
"github.com/energye/energy/example/browser-control/src"
)
//go:embed resources
var resources embed.FS
//go:embed libs
var libs embed.FS
func main() {
//全局初始化 每个应用都必须调用的
cef.GlobalCEFInit(&libs, &resources)
//可选的应用配置
cfg := cef.NewApplicationConfig()
var env = commons.Args.Args("env")
if env == "dev" {
//指定chromium的二进制包框架根目录, 不指定为当前程序执行目录
cfg.SetFrameworkDirPath("D:\\app.exe\\energy\\105.0.5195.127\\dev\\chromium-64")
}
//创建应用
cefApp := cef.NewApplication(cfg)
cefApp.SetOnBeforeChildProcessLaunch(func(commandLine *cef.TCefCommandLine) {
if env != "" {
commandLine.AppendSwitch("env", env)
}
})
//主进程窗口
src.MainBrowserWindow()
//运行应用
cef.Run(cefApp)
}

View File

@ -0,0 +1,3 @@
提取Energy压缩包动态链接库liblcl.dll到该目录下
libs目录下的文件会被编译到执行文件中

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>浏览器控制</title>
<style>
</style>
<script type="application/javascript">
let data = {
progress: 0.0,
isLoading: false,
canGoBack: false,
canGoForward: false,
}
let methods = {
//返回
goBack: function () {
ipc.emit("goBack")
},
//前进
goForward: function () {
ipc.emit("goForward")
},
//刷新
refresh: function () {
ipc.emit("refresh")
},
//打开指定URL
goUrl: function () {
let url = document.getElementById("url").value
ipc.emit("goUrl", [url])
}
}
//监听页面加载进度 progress: double 0 ~ 1
ipc.on("onLoadingProgressChange", function (progress) {
console.log("onLoadingProgressChange:", progress)
data.progress = progress
document.getElementById("state").innerHTML = "状态:" + (progress * 100)
});
//监听页面加载状态
// isLoading: true 加载中 false 加载完成
// canGoBack: true 可以后退 false 不可以后退
// canGoForward: true 可以前进 false 不可以前进
ipc.on("onLoadingStateChange", function (isLoading, canGoBack, canGoForward) {
console.log("onLoadingStateChange:", isLoading, canGoBack, canGoForward)
data.isLoading = isLoading
data.canGoBack = canGoBack
data.canGoForward = canGoForward
document.getElementById("refresh").disabled = isLoading
document.getElementById("goBack").disabled = !canGoBack
document.getElementById("goForward").disabled = !canGoForward
});
</script>
</head>
<body style="overflow: hidden;margin: 0px;padding: 0px;">
<div style="width: 100vw;height: 100vh;">
<div style="width: 100%;height: 32px;">
<span style="width: 150px;">
<button id="goBack" onclick="methods.goBack()">返回</button>
<button id="goForward" onclick="methods.goForward()">前进</button>
<button id="refresh" onclick="methods.refresh()">刷新</button>
</span>
<input id="url" style="width: calc(100vw - 200px);" value="https://note.yanghy.cn">
<span style="width: 50px;">
<button id="goUrl" onclick="methods.goUrl()">GO</button>
</span>
</div>
<iframe id="contentFrame" src="https://energy.yanghy.cn" style="width: 100%;height: calc(100vh - 64px);border: none;">
</iframe>
<div id="state" style="height: 32px;border: solid 1px gray;width: 100%;text-align: center;">
状态
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,92 @@
package src
import (
"fmt"
"github.com/energye/energy/cef"
"github.com/energye/energy/commons"
"github.com/energye/energy/ipc"
"github.com/energye/golcl/lcl"
"os"
)
func MainBrowserWindow() {
//只有启动主进程才会继续执行
if !commons.Args.IsMain() {
return
}
fmt.Println("os.Args", os.Args)
//主窗口的配置
//指定一个URL地址或本地html文件目录
cef.BrowserWindow.Config.DefaultUrl = "E:\\SWT\\gopath\\src\\github.com\\energye\\energy\\example\\browser-control\\resources\\index.html"
//窗口的标题
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")
//页面加载处理进度
event.SetOnLoadingProgressChange(func(sender lcl.IObject, browser *cef.ICefBrowser, progress float64) {
//参数-进度
args := ipc.NewArgumentList()
args.SetFloat64(0, progress)
//触发html页面监听的事件使用ipc通信发送给指定的浏览器页面
browserWindow.Chromium().Emit("onLoadingProgressChange", args, browserWindow.Browser)
})
//页面加载状态,根据状态判断是否加载完成,和是否可前进后退
event.SetOnLoadingStateChange(func(sender lcl.IObject, browser *cef.ICefBrowser, isLoading, canGoBack, canGoForward bool) {
//参数-加载状态,是否可前进,后退
args := ipc.NewArgumentList()
args.SetBool(0, isLoading)
args.SetBool(1, canGoBack)
args.SetBool(2, canGoForward)
//触发html页面监听的事件使用ipc通信发送给指定的浏览器页面
browserWindow.Chromium().Emit("onLoadingStateChange", args, browserWindow.Browser)
})
})
//创建窗口之后对对主窗口的属性、组件或子创建的创建
cef.BrowserWindow.SetBrowserInitAfter(func(browserWindow *cef.TCefWindowInfo) {
fmt.Println("SetBrowserInitAfter")
})
//页面按钮事件 跳转指定URL
ipc.IPC.Browser().On("goUrl", func(context ipc.IIPCContext) {
//参数
args := context.Arguments()
//URL参数
fmt.Println("goUrl", args.GetString(0))
//获得当前浏览器的window信息
info := cef.BrowserWindow.GetWindowInfo(context.BrowserId())
//得到页面上所有iframe,默认有一个主Frame
for _, frame := range info.Frames {
//页面内容是使用iframe实现的这个iframe不是主要的
if !frame.IsMain() {
frame.LoadUrl(args.GetString(0))
}
}
})
//页面按钮事件 返回
ipc.IPC.Browser().On("goBack", func(context ipc.IIPCContext) {
fmt.Println("goBack")
info := cef.BrowserWindow.GetWindowInfo(context.BrowserId())
info.Chromium().GoBack()
})
//页面按钮事件 前进
ipc.IPC.Browser().On("goForward", func(context ipc.IIPCContext) {
fmt.Println("goForward")
info := cef.BrowserWindow.GetWindowInfo(context.BrowserId())
info.Chromium().GoForward()
})
//页面按钮事件 刷新
ipc.IPC.Browser().On("refresh", func(context ipc.IIPCContext) {
fmt.Println("refresh")
info := cef.BrowserWindow.GetWindowInfo(context.BrowserId())
info.Chromium().Reload()
})
}

View File

@ -1 +0,0 @@
这个文件夹可存放lcllib等类库内置到执行文件中

View File

@ -0,0 +1,3 @@
提取Energy压缩包动态链接库liblcl.dll到该目录下
libs目录下的文件会被编译到执行文件中

View File

@ -217,7 +217,7 @@ func AppBrowserInit() {
browserWindow.Window.AddOnResize(func(sender lcl.IObject) bool {
//Browser是在chromium加载完之后创建, 窗口创建时该对象还不存在
if browserWindow.Browser != nil {
var target = &cef.GoEmitTarget{
var target = &cef.EmitTarget{
BrowseId: browserWindow.Browser.Identifier(),
FrameId: browserWindow.Browser.MainFrame().Id,
}
@ -240,7 +240,7 @@ func AppBrowserInit() {
browserWindow.Window.SetOnConstrainedResize(func(sender lcl.IObject, minWidth, minHeight, maxWidth, maxHeight *int32) {
//Browser是在chromium加载完之后创建, 窗口创建时该对象还不存在
if browserWindow.Browser != nil {
var target = &cef.GoEmitTarget{
var target = &cef.EmitTarget{
BrowseId: browserWindow.Browser.Identifier(),
FrameId: browserWindow.Browser.MainFrame().Id,
}
@ -301,7 +301,7 @@ func AppBrowserInit() {
popupWindow.Window.AddOnResize(func(sender lcl.IObject) bool {
//Browser是在chromium加载完之后创建, 窗口创建时该对象还不存在
if popupWindow.Browser != nil {
var target = &cef.GoEmitTarget{
var target = &cef.EmitTarget{
BrowseId: popupWindow.Browser.Identifier(),
FrameId: popupWindow.Browser.MainFrame().Id,
}
@ -318,7 +318,7 @@ func AppBrowserInit() {
popupWindow.Window.SetOnConstrainedResize(func(sender lcl.IObject, minWidth, minHeight, maxWidth, maxHeight *int32) {
//Browser是在chromium加载完之后创建, 窗口创建时该对象还不存在
if popupWindow.Browser != nil {
var target = &cef.GoEmitTarget{
var target = &cef.EmitTarget{
BrowseId: popupWindow.Browser.Identifier(),
FrameId: popupWindow.Browser.MainFrame().Id,
}
@ -351,7 +351,7 @@ func AppBrowserInit() {
fmt.Println("OnLoadingStateChange-ProcessType:", commons.Args.ProcessType(), "sender.Instance:", sender.Instance(), "browserId:", browser.Identifier(), "isLoading:", isLoading, "canGoBack:", canGoBack, "canGoForward:", canGoForward)
if isSendEmit {
info := cef.BrowserWindow.GetWindowInfo(browser.Identifier())
var target = &cef.GoEmitTarget{
var target = &cef.EmitTarget{
BrowseId: browser.Identifier(),
FrameId: browser.MainFrame().Id,
}
@ -368,7 +368,7 @@ func AppBrowserInit() {
//当刷新的是一个完整的浏览器时如果打开的新页面不是html dom这里的 emit 消息
fmt.Println("OnLoadingProgressChange-ProcessType:", commons.Args.ProcessType(), "browserId:", browser.Identifier(), "progress:", progress)
if isSendEmit {
var target = &cef.GoEmitTarget{
var target = &cef.EmitTarget{
BrowseId: browser.Identifier(),
FrameId: browser.MainFrame().Id,
}

2
go.mod
View File

@ -2,4 +2,4 @@ module github.com/energye/energy
go 1.18
require github.com/energye/golcl v0.0.0-20221019060700-9d0fe401620a
require github.com/energye/golcl v0.0.0-20221024100207-844863c6a85e

4
go.sum
View File

@ -1,2 +1,2 @@
github.com/energye/golcl v0.0.0-20221019060700-9d0fe401620a h1:hFDTA+SD6GCkbEHUTKnHyX/Bvnu6TikfFscMC86Nxv4=
github.com/energye/golcl v0.0.0-20221019060700-9d0fe401620a/go.mod h1:8JYrNlYBZ+XbHA99DUWvj5CqIp8txgYvMjL7ipAtLDE=
github.com/energye/golcl v0.0.0-20221024100207-844863c6a85e h1:GQW9Q6k1hwQgYw9wHKi+dcthWnZWDBrtyKBwrqCQn9M=
github.com/energye/golcl v0.0.0-20221024100207-844863c6a85e/go.mod h1:8JYrNlYBZ+XbHA99DUWvj5CqIp8txgYvMjL7ipAtLDE=