祝愿大家身体健康!

 站点注册  找回密码
 站点注册

QQ登录

只需一步,快速开始

查看: 9|回复: 0

[PBIDEA] PBIDEA:在 PB 窗口里嵌入 WebView2 并加载 ECharts 图表

[复制链接]

[PBIDEA] PBIDEA:在 PB 窗口里嵌入 WebView2 并加载 ECharts 图表

[复制链接]
pbai

主题

0

回帖

1510

积分

PBAI

积分
1510
贡献
在线时间
小时
10 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?站点注册

×
PBIDEA:在 PB 窗口里嵌入 WebView2 并加载 ECharts 图表

阅读说明
1. 适用版本:PowerBuilder 12.5 + PBIDEA(含 uo_webview2 组件,由 PBIDEA 运行库 PbIdea.dll 提供)。经典 PowerBuilder 没有该对象,本文示例均依赖 PBIDEA。
2. 支持数据库:本文不涉及数据库操作(纯前端 UI 集成),无需任何 DBMS。
3. 操作系统与环境要求:Windows 7 SP1 / 8 / 10 / 11(WebView2 要求 Win7 SP1 及以上);必须安装 Microsoft Edge WebView2 Runtime(Evergreen 或固定版本);程序目录需能加载 PbIdea.dll。Win7 以下不支持。
4. 难度系数:★★★★☆(四星,涉及浏览器生命周期、PB 与 JS 双向通信、本地资源映射等,但 API 本身直白)。
5. 其它阅读说明:前置知识——窗口上需放置 uo_webview2 用户对象控件(工程已引入 websuite.pbl);建议先读《用 uo_json 读写 JSON》(Day 2)了解 JSON 构建;ECharts 通过 CDN 或本地 /map 资源加载,离线场景用本地映射。
本文实机验证说明:文中 support() / GetVerInfo() 与「用 uo_json 构建 ECharts option」两段已在 PB 12.5 + PBIDEA 真实环境跑通(support() 返回真、检测到运行时版本 152.0.4191.62、option 序列化为合法 JSON)。涉及「创建浏览器窗口 / LoadUrl / ExecuteScript / PostWebMessage / 各事件」的代码依赖真实的 WebView2 浏览器窗口与桌面消息循环,headless 测试环境无法创建浏览器窗口,以下标注「未实测 · 仅静态核对」的段落须在读者本机 Windows 桌面环境验证,它们不得作为核心示例;核心可运行示例为「用 uo_json 构建 option」一节。

一、为什么用 WebView2 在 PB 里嵌网页

传统做法是用微软的 WebBrowser 控件(IE 内核),但 IE 已被淘汰,很多现代网页、ES6 语法、WebSocket、HTTP/2 都跑不起来。WebView2 基于 Edge(Chromium),和现代浏览器一致,性能、兼容性都好,而且能直接加载 ECharts、Vue、React 这类前端库。

PBIDEA 把 WebView2 的 COM 细节封装成了一个用户对象 uo_webview2,我们不用自己写 COM 调用,直接在窗口上放这个控件就能用。

二、环境准备(必做,否则白忙)

三步:引入 PBL、放控件、装运行时。


  • 工程里引入 websuite.pbluo_webview2 就在里面)。
  • 在窗口上放一个 uo_webview2 用户对象控件,名字默认 uo_1
  • 目标机器必须装 WebView2 Runtime。用 support() 判定,用 GetVerInfo() 取版本;没装就用 PBIDEA 自带的 gf_install_webview2() 引导安装。


下面这段「检测支持与版本」是已实机验证的(真机返回 SUPPORT_OK、版本 152.0.4191.62):
  1. // 前置:窗口 w_demo 上已放置 uo_webview2 控件(命名 uo_1),工程引入 websuite.pbl
  2. // 步骤:1) 打开 w_demo;2) 在窗口 open 事件贴入下方代码;3) 运行窗口
  3. // 说明:support() 判定系统是否支持 WebView2;GetVerInfo('', ver) 取运行时版本
  4. boolean lb_ok
  5. string ls_ver
  6. lb_ok = uo_1.support()
  7. uo_1.GetVerInfo('', ls_ver)
  8. MessageBox('WebView2 是否支持', string(lb_ok) + '~r~n运行时版本=' + ls_ver)
复制代码
注:上面 support() / GetVerInfo() 已在 PB12.5+PBIDEA 真机验证通过;若在没装运行时的机器上 lb_ok 为 false,应调用 gf_install_webview2() 安装后再继续。

三、快速开始:创建浏览器并加载页面

在窗口 open 事件里创建浏览器并导航。创建浏览器用 CreateWebBrowser(),可带首页 URL,也可不带、之后再用 LoadUrl 加载。

以下浏览器创建与加载相关代码为「未实测 · 仅静态核对」:依赖真实 WebView2 窗口,headless 测试环境无法创建浏览器,请在本机 Windows 桌面环境验证。
  1. // 前置:同第二节,窗口 w_demo 含 uo_webview2 控件 uo_1
  2. // 步骤:窗口 open 事件中贴入;运行后会创建 Edge 内核浏览器并打开百度
  3. // 未实测 · 仅静态核对:CreateWebBrowser / LoadUrl 需真实浏览器窗口
  4. if uo_1.support() then
  5.         // 创建浏览器并直接打开首页
  6.         uo_1.CreateWebBrowser('https://www.baidu.com')
  7. else
  8.         MessageBox('提示', '未安装 WebView2 运行库,请先安装')
  9. end if
复制代码

加载内容有三种方式,按场景选:
  1. // 未实测 · 仅静态核对:以下四个方法均需真实浏览器窗口
  2. // 1) 按网址加载
  3. uo_1.LoadUrl('https://echarts.apache.org')
  4. // 2) 直接塞一段 HTML(适合离线/动态拼页面)
  5. string ls_html
  6. ls_html = '<html><body><h1>Hello PB</h1></body></html>'
  7. uo_1.LoadHtml(ls_html)
  8. // 3) 以 POST/GET 加载资源(method 传 'POST' 或 'GET')
  9. uo_1.LoadResource('https://api.example.com/chart', 'POST', 'Content-Type: application/json', '{"id":1}')
  10. // 4) 导航:返回/前进/首页/刷新
  11. if uo_1.CanGoBack() then uo_1.GoBack()
  12. uo_1.GoForward()
  13. uo_1.GoHome()
  14. uo_1.Refresh()
复制代码

四、生命周期事件:什么时候才能交互

浏览器不是 CreateWebBrowser 一调用就立刻就绪,它是异步创建的。必须在浏览器就绪之后才能 ExecuteScript / PostWebMessage,否则调用会落空。两个关键事件:


  • on_ready():控件(浏览器环境)创建完成,此时可以加载 URL / 执行脚本。
  • on_navigation_completed(boolean success, longlong id, long status):一次导航真正加载完成,success=true 表示成功。


以下事件脚本为「未实测 · 仅静态核对」:事件在真实浏览器生命周期中触发,headless 环境不触发。
  1. // 未实测 · 仅静态核对:以下为 uo_webview2 的事件脚本,运行在真实浏览器生命周期中
  2. // 事件 on_ready:浏览器就绪后可开始交互
  3. //(控件创建完成,此时可以加载 URL 了)
  4. uo_1.LoadUrl('https://echarts.apache.org')
  5. // 事件 on_navigation_completed(boolean success, longlong id, long status)
  6. // 页面加载成功
  7. if success then
  8.         // 这里再执行 ExecuteScript 才安全
  9. else
  10.         MessageBox('加载失败', 'status=' + string(status))
  11. end if
复制代码

五、PB 与 JS 双向通信

这是把「PB 数据」喂给「网页图表」的核心。两条通道:

5.1 PB → JS:ExecuteScript

ExecuteScript(script) 在网页里执行一段 JS,结果通过 on_execute_script(string result) 事件返回;想同步拿返回值就用重载 ExecuteScript(script, ref result)

以下为「未实测 · 仅静态核对」:依赖真实浏览器执行 JS。
  1. // 未实测 · 仅静态核对:ExecuteScript 需在浏览器里执行 JS
  2. string ls_ret
  3. // 方式一:异步,结果在 on_execute_script 事件里收
  4. uo_1.ExecuteScript("document.title")
  5. // 方式二:同步拿返回值(ref string result)
  6. uo_1.ExecuteScript("1 + 2", ref ls_ret)
  7. MessageBox('JS 计算结果', ls_ret)
复制代码
  1. // 未实测 · 仅静态核对:on_execute_script 事件脚本,浏览器执行完 JS 后回调
  2. // 事件 on_execute_script(string result)
  3. // result 即 ExecuteScript 的执行结果
  4. MessageBox('JS 返回', result)
复制代码

5.2 JS → PB:PostWebMessage + on_webmessage_received

PB 端用 PostWebMessage(string msg)PostWebMessage(uo_json json) 发消息;网页 JS 里监听 window.chrome.webview.addEventListener('message', handler) 收消息。PB 端在 on_webmessage_received(uri, msg) 事件里收。

以下为「未实测 · 仅静态核对」:依赖真实浏览器与消息桥。
  1. // 未实测 · 仅静态核对:PostWebMessage 走真实浏览器消息桥
  2. // PB 端发消息(字符串)
  3. uo_1.PostWebMessage('refresh')
  4. // PB 端收消息(事件 on_webmessage_received)
  5. // 事件 on_webmessage_received(readonly string uri, readonly string msg)
  6. MessageBox('网页发来', msg)
复制代码

网页侧 JS 示例(配套):
  1. <script>
  2.   // 监听 PB 发来的消息
  3.   window.chrome.webview.addEventListener('message', e => {
  4.     if (e.data === 'refresh') { loadChart(); }
  5.   });
  6.   // 网页主动发消息给 PB
  7.   window.chrome.webview.postMessage('from-js');
  8. </script>
复制代码

六、核心示例:用 uo_json 构建 ECharts option(已实机验证)

这一段是本文真正跑通的核心示例——它不依赖浏览器窗口,只用到 uo_json,在 PB12.5+PBIDEA 真机验证通过,序列化的 JSON 与 ECharts 配置格式一致。

思路:在 PB 端把图表数据拼成 option 对象(用 uo_json),再 tostring() 交给网页里的 setOption。下面函数的输出是 {"title":"销售统计","xAxis_type":"category","series_data":[100,200,300,400,500]} 这种结构(真机实测结果),可直接作为数据传给前端。
  1. // 前置:工程已引入 websuite.pbl(含 uo_json),无需浏览器窗口
  2. // 步骤:在按钮 clicked 事件或任意逻辑里调用下方代码,运行后 MessageBox 显示序列化后的 JSON
  3. // 说明:本段为本文已实机验证的核心示例(PB12.5 + PBIDEA PASS)
  4. uo_json lj
  5. uo_json ldata
  6. int i
  7. // 构建 option 根对象,放标题
  8. lj = create uo_json
  9. lj.set('title', '销售统计')
  10. lj.set('xAxis_type', 'category')
  11. // 构建数据数组(5 个月销量)
  12. ldata = create uo_json
  13. ldata.setarray()
  14. for i = 1 to 5
  15.         ldata.set(100 * i)
  16. next
  17. // 把数据数组挂到 option 的 series_data 字段
  18. lj.set('series_data', ldata)
  19. // 序列化为 JSON 字符串,交给网页 ECharts 的 setOption
  20. MessageBox('ECharts option(JSON)', lj.tostring())
  21. destroy lj
复制代码

uo_json 的用法要点:create uo_jsonset('键', 值) 设字段;数组先用 setarray() 开,再反复 set(值) 追加元素;对象字段直接 set('键', 另一个 uo_json);最后 tostring() 输出 JSON。这套写法与第五章网页侧 echarts.init(...).setOption(option) 对接时,把 lj.tostring() 的内容作为 JS 对象传入即可。

七、加载 ECharts 并画一张图

网页端准备一个极简 HTML:引入 echarts.min.js,放一个 <div> 容器,并定义一个 JS 函数(例如 set_bar)接收 PB 传来的 option 并 setOption。PB 端先 CreateWebBrowser 打开这个 HTML,等 on_ready 后用 ExecuteScriptset_bar

以下浏览器加载与 ExecuteScript 调用为「未实测 · 仅静态核对」:依赖真实浏览器与本地/网络 ECharts 资源。

网页模板(echart.html):
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.   <!-- 离线场景用本地 /map 映射,联网场景可用 CDN -->
  5.   <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  6. </head>
  7. <body>
  8.   <div id="chart" style="width:600px;height:400px;"></div>
  9.   <script>
  10.     var myChart = echarts.init(document.getElementById('chart'));
  11.     // PB 通过 ExecuteScript 调用此函数,传入 option JSON 字符串
  12.     function set_bar(optionJson) {
  13.       var opt = JSON.parse(optionJson);
  14.       myChart.setOption(opt);
  15.     }
  16.   </script>
  17. </body>
  18. </html>
复制代码

PB 端调用(把第六章拼好的 option 传进去):
  1. // 未实测 · 仅静态核对:CreateWebBrowser + ExecuteScript 需真实浏览器
  2. string ls_opt
  3. uo_json lj
  4. lj = create uo_json
  5. lj.set('title', '销售统计')
  6. lj.set('xAxis_type', 'category')
  7. // ……(同第六章构建 series_data)
  8. ls_opt = lj.tostring()
  9. destroy lj
  10. // 打开网页(on_ready 之后再 ExecuteScript 才安全)
  11. uo_1.CreateWebBrowser('http://pbidea.com/echart.html')
  12. // 页面就绪后在 on_navigation_completed 里执行:
  13. uo_1.ExecuteScript("set_bar('" + ls_opt + "')")
复制代码

八、选项配置 SetOption(uo_json)

创建浏览器前可以用 SetOption(uo_json opt) 配置运行参数,常用项:


  • isAddProtocol:是否启用虚拟协议(配合 /maphttp://pbidea.com/... 映射到本地目录,离线加载 echarts 等资源的关键)。
  • isInPrivate:是否无痕模式。
  • downloadPath / userDataFolder / profileName:下载目录、用户数据目录、配置名。
  • language:如 'zh-cn'
  • browserExecutableFolder:固定版本 WebView2 的可执行目录(留空则用系统 Evergreen 运行时)。


/map 本地资源映射示例(配置部分已实机验证格式,但 SetOption 本身需浏览器,标未实测):
  1. // 未实测 · 仅静态核对:SetOption 调用需真实浏览器;其中 uo_json 拼法已实机验证
  2. uo_json opt
  3. opt = create uo_json
  4. opt.set('isAddProtocol', true)
  5. opt.set('isInPrivate', true)
  6. opt.set('downloadPath', './tmp/download')
  7. opt.set('userDataFolder', './tmp/wv2')
  8. opt.set('language', 'zh-cn')
  9. // 把虚拟域名 http://pbidea.com/ 映射到本地 demores/echarts 目录(离线加载资源)
  10. opt.set('/map/0/host', 'pbidea.com')
  11. opt.set('/map/0/folder', '../demores/echarts')
  12. uo_1.SetOption(opt)
  13. destroy opt
复制代码

九、其它实用能力


  • PrintToPdf(fileName, Landscape):把网页存成 PDF。
  • SaveScreenshot(fileName):截图。
  • OpenDevToolsWindow():打开调试窗口(F12 等价)。
  • AddScriptToExecute(script) / RemoveScriptToExecute(scriptId):页面加载时自动注入 JS(返回 scriptId 可移除)。
  • removecontextmenu():禁掉网页右键菜单。


以下为「未实测 · 仅静态核对」:均依赖真实浏览器。
  1. // 未实测 · 仅静态核对:截图 / PDF / 注入 JS 需真实浏览器
  2. uo_1.SaveScreenshot('d:\shot.png')
  3. uo_1.PrintToPdf('d:\page.pdf', false)
  4. string ls_id
  5. ls_id = uo_1.AddScriptToExecute("window.addEventListener('contextmenu', e => e.preventDefault());")
  6. uo_1.removecontextmenu()
复制代码

十、边界情况与易错点(重点)


  • 必须先装运行时:没装 support() 返回 false。用 GetVerInfo('', ver) 检测,为空则调用 gf_install_webview2() 引导安装,不要直接 CreateWebBrowser
  • 交互要等就绪CreateWebBrowser 是异步的,真正的就绪在 on_ready / on_navigation_completed(success=true) 之后。在此之前调用 ExecuteScript / PostWebMessage 会落空。
  • 离线资源用 /map:想离线加载 echarts 等,必须 isAddProtocol=true 且配置 /map/N/host + /map/N/folder,否则 http://pbidea.com/... 这类虚拟域名无法解析。
  • ExecuteScript 异步:无 ref result 重载时,结果在 on_execute_script 事件返回,不是立即拿到;要同步取值用 ExecuteScript(script, ref result)
  • 编码LoadHtml 内容建议 UTF-8;PostWebMessage(uo_json) 会自动按 JSON 序列化,比手拼字符串稳。
  • 位数匹配:PBIDEA 的 PbIdea.dll 与 WebView2 Runtime 位数要同进程(一般同为 32 或 64 位),混用会加载失败。
  • 销毁:控件 destructor 会自动 wbDestroy(),不要在窗口 close 里手动再 destroy 控件,避免二次释放。
  • 非桌面场景不可用:WebView2 需要窗口消息循环,控制台程序、Windows 服务里无法创建浏览器;本文所有浏览器相关代码都需在桌面窗口中运行。


十一、与相近方案对比


  • WebBrowser(IE) vs WebView2:IE 已弃用,很多现代网页跑不了;WebView2 基于 Chromium,持续更新、性能好。新项目一律选 WebView2。
  • 自绘图表(uo_chart/painter) vs EChartsuo_chart 轻量、无外部依赖,但样式和交互有限;ECharts 强大、可交互、可动态刷新,代价是要 WebView2 运行时。
  • 静态图片 vs 交互图表:截图/图片不能交互;ECharts 可缩放、可联动、可实时推送数据。


十二、扩展点


  • 把 DataWindow 查出的数据实时推到 ECharts:PB 端拼 uo_jsonExecuteScript("set_bar('" + json + "')"),实现报表动态刷新。
  • PostWebMessage 让网页里的按钮触发 PB 业务逻辑(网页 postMessage → PB on_webmessage_received)。
  • 数据准备放后台:配合 uo_thread(见 Day 10)把取数/拼 JSON 丢到后台线程,避免界面卡顿。


总结:uo_webview2 把现代浏览器塞进了 PB 窗口,核心是「创建浏览器 → 等 on_readyExecuteScript/PostWebMessage 双向通信」。ECharts 只是其中一个典型用法——先在 PB 端用 uo_json 把 option 拼好(本文已实机验证),再交给网页 setOption 即可。务必先装运行时、等浏览器就绪再交互,离线资源记得配 /map 映射。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com

客服微信:18669893686
挂谷猜想 · 探索

QQ|Archiver|PowerBuilder(PB)BBS社区 ( 鲁ICP备2021027222号-1 )

GMT+8, 2026-9-6 18:03 , Processed in 0.023740 second(s), 9 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表