# 简介
**关于PyWkeMiniblink**
PyWkeMiniblink 是 [Miniblink](https://weolar.github.io/miniblink/)的Python绑定,参考了上游项目[MBPython](https://github.com/lochen88/MBPython)。
PyWkeMiniblink: [项目地址](https://github.com/StoneFlaw/PyWkeMiniblink) / [在线文档](https://pywkeminiblink.readthedocs.io/zh-cn/latest/) / [PYPI主页](https://pypi.org/project/WkeMiniblink/)
**关于Miniblink**
Miniblink 是 chromium的精简版,删除了音视频功能,原接口参见[官方接口文档](https://miniblink.net/views/doc/index.html),更完整的参见docs/source/wke.h 。
# 使用
## 安装
```shell
#安装依赖pywin32
pip3 install pywin32
#安装本地文件xx版本
pip3 install WkeMiniblink-xx-py3-none-any.whl
#从PYPI安装
pip3 install WkeMiniblink
```
## 示例
```python
# -*- coding:utf-8 -*-
import os,sys,platform,time
import win32gui
from wkeMiniblink.wke import *
from wkeMiniblink.wkeEvent import *
from wkeMiniblink.wkeWin32 import *
if __name__=='__main__':
webview = WebWindow()
webview.create(0,0,0,800,600)
def OnCloseEvent(context,*args,**kwargs):
win32gui.PostQuitMessage(0)
return True
Wke.event.onWindowClosing(webview,OnCloseEvent,param='App Quit')
webview.loadURL('https://www.w3school.com.cn/jsref/index.asp')
webview.showWindow(True)
Wke.runMessageLoop()
```
# 说明
## 全局接口Wke
### DLL加载
目前版本采用PyWkeMiniblink包初始化时自动加载dll。
32位模式加载miniblink_4975_x32.dll,64位模式加载miniblink_4975_x64.dll。
搜索DLL所在位置的顺序:
1. 脚本模式下python.exe所在在目录是否含有dll,PyInstaller打包模式下Package根目录否含有dll;
2. PyWkeMiniblink包所在目录下的bin目录是否含有dll;
3. 系统环境变量的目录下是否含有dll;
## 创建网页对象的方式
### 网页视图WebView
网页视图包括加载/渲染/设置/Js/Cookie等,但并不包括实际窗口功能。
### 网页窗口WebWindow
网页窗口继承自WebView,包括窗口功能。
1. WebWindow
WebWindow.create(0,x,y,h,w)由miniblink创建一个网页窗口,绘制与消息处理由miniblink内部处理;
无需额外处理窗口消息与绘制过程。
2. WebWindow
WebWindow.build(父窗口hwnd,x,y,h,w)在父窗口内部,由miniblink创建一个网页窗口;
需要关联处理父窗口与本窗口消息流程,主要为退出和调整大小的同步。
3. WebView
WebView.bind(父窗口hwnd,x,y,w,h)在一个已经创建的父窗口hwnd上绑定一个网页视图;
需要处理父窗口的消息流程,以及自身的离屏绘制。
## 窗口消息分发
三种消息读取分发循环:Wke.runMessageLoop()、win32gui.PumpMessages()、wkePumpMessages(block)
自定义消息分发循环时可以参考wkePumpMessages的两种分发循环。
阻塞式
```python
while True:
res = windll.user32.GetMessageA(byref(msg), None, 0, 0)
if res != 0:
windll.user32.TranslateMessage(byref(msg))
windll.user32.DispatchMessageA(byref(msg))
elif res == 0:
windll.user32.TranslateMessage(byref(msg))
windll.user32.DispatchMessageA(byref(msg))
break
else:
raise RuntimeError(f"GetMessage {res}")
```
非阻塞式
```python
while True:
res = windll.user32.PeekMessageA(byref(msg), None,0, 0, 1)
if res != 0:
windll.user32.TranslateMessage(byref(msg))
windll.user32.DispatchMessageA(byref(msg))
if msg.message in[WM_QUIT]:
break
else:
time.sleep(0.05)
```
## 窗口消息处理
*当WebView/WebWindow绑定在父窗口下时,需要修改父窗口的消息处理函数,实现WebView/WebWindow子窗口的消息处理过程。*
wkeWin32的**HwndMsgAdapter**使用自身的消息处理流程替换指定父窗口的消息处理,接受外部注册的python函数处理指定的消息。
替换后对于已经注册的消息,使用注册函数来响应,如果函数返回None,则继续调用父窗口的默认消息处理流程,若不为None则不调用;对于没注册的消息则使用父窗口的默认消息处理流程。
注册的消息响应函数可以有1~5个参数,如下:
| Arg1 | Arg2 | Arg3 | Arg4 | Arg5 |
| :-----: | :----: | :----: | :----: | :----: |
| webview | hwnd | msg | wParam | lParam |
| self | hwnd | msg | wParam | lParam |
| hwnd | msg | wParam | lParam | |
| hwnd | wParam | lParam | | |
| wParam | lParam | | | |
| self | | | | |
| hwnd | | | | |
HwndMsgAdapter的消息处理流程调用注册的消息响应函数时:
- 参数hwnd/msg/wParam/lParam 使用父窗口的处理流程的句柄/消息/参数带入
- 有5个参数时第一个参数名为self或webview,self则对应HwndProcAdapter类实例带入,webview对应HwndProcAdapter类实例的webview属性带入
- 有1个参数时同上,参数名为其他时,以消息窗口句柄hwnd带入
Example:
```python
x,y,w,h = 0,0,640,480
hwnd = wkeCreateWindow('Window',x,y,w,h)
webview.build(hwnd,x,y,w,h)
a = HwndMsgAdapter()
def wkeMsgProcQuit(webview,hwnd,msg,wParam,lParam):
win32gui.PostQuitMessage(0)
return
a.registerMsgProc(WM_SIZE,wkeMsgProcResize)
a.registerMsgProc(WM_DESTROY,wkeMsgProcQuit)
a.attach(hwnd,webview)
webview.loadURL("http://192.168.1.1")
....
```
***需要注意窗:替换消息处理函数与消息处理循环之间的穿插wke的某些窗体控制函数可能导致问题!***
## 事件WkeEvent
*Wke关于webview的事件管理是基于WebView,一个WebView对象的打开/关闭/加载/绘制等一系列事件都会触发执行其事件响应函数。*
**WkeEvent以【webview的id】【事件名称的id】 为二元结构,管理事件响应函数及其上下文。**
### 注册事件处理函数onXXXX(webview,func,param)
1. 接受XXX事件处理的网页对象webview
2. XXX事件处理函数func
3. 注册前和调用后的贯穿参数param
### 事件处理函数func(context,*args,**kwargs)
- 经WkeEvent的翻译,传递给事件响应函数的上下文context是个字典,如下:
context = {"id":eventid,"param":param,"func":func,"webview":webview,"id":webview.cId,"event":event}
- param是注册回调函数时OnXXX(func,param)绑定的任意python object对象,func是绑定的python回调函数
- 不同的事件有特定的扩展参数,都写在kwargs中,例如Alert事件中通知消息就在kwargs["msg"]中
Example:
```python
#//python 事件响应函数void OnAlertEvent(context:dict,kwargs={msg:str})
#/*typedef void(WKE_CALL_TYPE*wkeAlertBoxCallback)(wkeWebView webView, void* param, const wkeString msg);*/
# OnAlertCallback回调函数执行时包含: kwargs["msg"]
def main():
Wke.setCookieAndStagePath(cookie=f'{father_folder }/build/cookie.dat',localStage=f'{father_folder }/build/LocalStage')
webview = WebWindow()
webview.create(0,0,0,800,600)
def OnAlertEvent(context,*args,**kwargs):
param = context["param"]
print(f"{str(param)} \nargs:{pformat(args)}\nkwargs:{pformat(kwargs)}\n=======================\n")
msg = kwargs["msg"]
windowTitle = ""
result = win32gui.MessageBox(0, msg, windowTitle, win32con.MB_OK)
return result
def OnCloseEvent(context,*args,**kwargs):
win32gui.PostQuitMessage(0)
return True
webview.onAlertBox(OnAlertEvent,param='Alert')
webview.onWindowClosing(OnCloseEvent,param='App Quit')
#webview.loadURL('https://www.w3school.com.cn/tiy/t.asp?f=jsck_alert_2')
webview.loadFile(f'{father_folder}/res/testdata/alert.html')
webview.showWindow(True)
Wke.runMessageLoop()
```
Webview绑定了一系列事件回调函数注册方法,和使用全局Wke.event管理器注册等价:
```python
Wke.event.OnPaintEvent(webview,param,*args,**kwargs)
webview.OnPaintEvent(param,*args,**kwargs)
```
unittest/testWebViewOnEvent.py检查WkeEvent所有事件是否在WebView都有对应的绑定实现,并生成所需要的实现翻译代码。
### Javascript 扩展
静态类函数:Wke.extend(func,name,param):
使用一个指定的python函数作为扩展的js函数
Example:
```python
webview = WebWindow()
webview.create(0,0,0,800,600)
def pyAction(**kwargs):
es=kwargs['es']
context =kwargs['param']
webview = context
arg_count=Wke.jsArgCount(es)
val_ls=Wke.getJsArgs(es,arg_count)
webview.runJsCode('alert("jsCallpy'+str(val_ls)+'")')
return
Wke.extend(pyAction,'jsCallpy', param=webview)
```
在html/js 中调用
```html
<button onclick="jsCallpy('jsCallpy', 666)" style='margin-right: 20px;cursor: pointer;'>jsCallpy</button>
```
## Javascript 集成
WebView/WebWindows的runJsCode/runJsFile/runJsFunc方法支持Python端在网页对象中运行js代码。
## 其它WkeWin32
WkeWin32包含了Win32相关下面的辅助方法:
wkeSetIcon/wkeCreateWindow/wkeCreateTransparentWindow/wkeSetWindowLongHook/wkeGetWindowLongHook 等方法;
定时类WkeTimer/截屏类WkeSnapShot
# 插件支持
Miniblink supports NPAPI plugins.
未验证
# 离屏渲染
WebView.bind(父窗口hwnd,x,y,w,h)在一个已经创建的父窗口hwnd上绑定一个网页视图,然后额外的处理父窗口的消息,以及父窗口到网页视图的绘制。
参见wkeWin32ProcMsg中WebViewWithProcHwnd和example/bindWebview.py
# 发布
## pyinstaller
(Pyinstaller>=6.0.0 )
- 在Pyinstaller打包 one dir(-D 目录模式)时,除可执行文件外,其余文件都将被转移到 _internal 文件夹
即Package根目录
- 在Pyinstaller打包 one file (-F 文件模式)时,除可执行文件外,其余文件都将被转移到一个临时文件夹
即Package根目录
- 在Python解释器模式下,以Lib\site-packages
以此为Package的根目录
# 其他问题
## Ctypes数据类型
参见prepare.py.translate()与wke.h.json
## Alert/Prompt/Confirm
Minibilink支持Alert和Confirm,但是Prompt没实现。
可以使用wkeEvent的回调函数额外实现相应的GUI及其返回值控制,参见examples.
## PromptBoxCallback的Py形参和返回值
正常情况下
```
typedef bool(WKE_CALL_TYPE*wkePromptBoxCallback)(wkeWebView webView, void* param, const wkeString msg, const wkeString defaultResult, wkeString result);
<<=>>
CFUNCTYPE(c_bool,_LRESULT,c_void_p,c_char_p,c_char_p,c_void_p)
```
原回调函数返回值为c_bool,为保持形参形式一致,不做按引用传参数带出返回值,取消形参result,而是python的返回值。
实际python回调函数返回值为Str(有字符串确定输入)/None(取消输入)
## wkeGetString/wkeSetString/String/StingW
Miniblink文档中String对应utf8*而StringW对应utf16*
wkeEvent.py中32位下wkeGetStringW(str)运行正常,但是64位会c函数内部读异常
现在默认wkeString全部是utf8,改为wkeGetString(str),然后做binary->str的解码
## wkeString的Ctypes参数类型
将只读wkeString 全翻译为c_char_p,方便ctypes自动转换字符串。
如果需要写入wkeString,就翻译为c_void_p (c_char_p自动翻译为None)
```
#wkeString:c_void_p,text:str
utf8 = text.encode(encoding)
l = len(utf8)
mb.wkeSetString(cast(wkeString,c_char_p),utf8,l)
```
wkePromptBoxCallback的最后一个参数为wkeString,需要作为传参返回,填入字符串。所以wkeString翻成c_void_p
# TODO
Wke/WebView的job/request有些地方未修订验证
下载/插件/通信事件回调 暂都未验证
RunJs验证了参数功能正常,但是返回值总是None
# [Contact Us](mailto://wyh917@163.com)
Raw data
{
"_id": null,
"home_page": null,
"name": "WkeMiniblink",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "Miniblink Wke webbrowser",
"author": "StoneFlaw",
"author_email": "wyh917@163.com",
"download_url": null,
"platform": null,
"description": "# \u7b80\u4ecb\r\n\r\n\r\n\r\n**\u5173\u4e8ePyWkeMiniblink**\r\n\r\nPyWkeMiniblink \u662f [Miniblink](https://weolar.github.io/miniblink/)\u7684Python\u7ed1\u5b9a\uff0c\u53c2\u8003\u4e86\u4e0a\u6e38\u9879\u76ee[MBPython](https://github.com/lochen88/MBPython)\u3002\r\n\r\nPyWkeMiniblink\uff1a [\u9879\u76ee\u5730\u5740](https://github.com/StoneFlaw/PyWkeMiniblink) / [\u5728\u7ebf\u6587\u6863](https://pywkeminiblink.readthedocs.io/zh-cn/latest/) / [PYPI\u4e3b\u9875](https://pypi.org/project/WkeMiniblink/)\r\n\r\n**\u5173\u4e8eMiniblink**\r\n\r\nMiniblink \u662f chromium\u7684\u7cbe\u7b80\u7248\uff0c\u5220\u9664\u4e86\u97f3\u89c6\u9891\u529f\u80fd,\u539f\u63a5\u53e3\u53c2\u89c1[\u5b98\u65b9\u63a5\u53e3\u6587\u6863](https://miniblink.net/views/doc/index.html),\u66f4\u5b8c\u6574\u7684\u53c2\u89c1docs/source/wke.h \u3002\r\n\r\n\r\n\r\n# \u4f7f\u7528\r\n\r\n## \u5b89\u88c5\r\n\r\n```shell\r\n#\u5b89\u88c5\u4f9d\u8d56pywin32\r\npip3 install pywin32\r\n#\u5b89\u88c5\u672c\u5730\u6587\u4ef6xx\u7248\u672c\r\npip3 install WkeMiniblink-xx-py3-none-any.whl\r\n#\u4ecePYPI\u5b89\u88c5\r\npip3 install WkeMiniblink\r\n```\r\n\r\n\r\n\r\n## \u793a\u4f8b\r\n\r\n```python\r\n# -*- coding:utf-8 -*-\r\nimport os,sys,platform,time\r\nimport win32gui\r\nfrom wkeMiniblink.wke import *\r\nfrom wkeMiniblink.wkeEvent import *\r\nfrom wkeMiniblink.wkeWin32 import *\r\n\r\nif __name__=='__main__':\r\n webview = WebWindow()\r\n webview.create(0,0,0,800,600)\r\n def OnCloseEvent(context,*args,**kwargs):\r\n win32gui.PostQuitMessage(0)\r\n return True\r\n Wke.event.onWindowClosing(webview,OnCloseEvent,param='App Quit')\r\n webview.loadURL('https://www.w3school.com.cn/jsref/index.asp')\r\n webview.showWindow(True)\r\n Wke.runMessageLoop()\r\n```\r\n\r\n# \u8bf4\u660e\r\n\r\n## \u5168\u5c40\u63a5\u53e3Wke\r\n\r\n### DLL\u52a0\u8f7d\r\n\r\n\u76ee\u524d\u7248\u672c\u91c7\u7528PyWkeMiniblink\u5305\u521d\u59cb\u5316\u65f6\u81ea\u52a8\u52a0\u8f7ddll\u3002\r\n\r\n32\u4f4d\u6a21\u5f0f\u52a0\u8f7dminiblink_4975_x32.dll,64\u4f4d\u6a21\u5f0f\u52a0\u8f7dminiblink_4975_x64.dll\u3002\r\n\r\n\u641c\u7d22DLL\u6240\u5728\u4f4d\u7f6e\u7684\u987a\u5e8f:\r\n\r\n1. \u811a\u672c\u6a21\u5f0f\u4e0bpython.exe\u6240\u5728\u5728\u76ee\u5f55\u662f\u5426\u542b\u6709dll\uff0cPyInstaller\u6253\u5305\u6a21\u5f0f\u4e0bPackage\u6839\u76ee\u5f55\u5426\u542b\u6709dll;\r\n2. PyWkeMiniblink\u5305\u6240\u5728\u76ee\u5f55\u4e0b\u7684bin\u76ee\u5f55\u662f\u5426\u542b\u6709dll;\r\n3. \u7cfb\u7edf\u73af\u5883\u53d8\u91cf\u7684\u76ee\u5f55\u4e0b\u662f\u5426\u542b\u6709dll;\r\n\r\n\r\n\r\n## \u521b\u5efa\u7f51\u9875\u5bf9\u8c61\u7684\u65b9\u5f0f\r\n\r\n### \u7f51\u9875\u89c6\u56feWebView\r\n\r\n\u7f51\u9875\u89c6\u56fe\u5305\u62ec\u52a0\u8f7d/\u6e32\u67d3/\u8bbe\u7f6e/Js/Cookie\u7b49,\u4f46\u5e76\u4e0d\u5305\u62ec\u5b9e\u9645\u7a97\u53e3\u529f\u80fd\u3002\r\n\r\n### \u7f51\u9875\u7a97\u53e3WebWindow\r\n\r\n\u7f51\u9875\u7a97\u53e3\u7ee7\u627f\u81eaWebView\uff0c\u5305\u62ec\u7a97\u53e3\u529f\u80fd\u3002\r\n\r\n1. WebWindow\r\n \tWebWindow.create(0,x,y,h,w)\u7531miniblink\u521b\u5efa\u4e00\u4e2a\u7f51\u9875\u7a97\u53e3\uff0c\u7ed8\u5236\u4e0e\u6d88\u606f\u5904\u7406\u7531miniblink\u5185\u90e8\u5904\u7406\uff1b\r\n\r\n \u200b\t\u65e0\u9700\u989d\u5916\u5904\u7406\u7a97\u53e3\u6d88\u606f\u4e0e\u7ed8\u5236\u8fc7\u7a0b\u3002\r\n\r\n2. WebWindow\r\n \tWebWindow.build(\u7236\u7a97\u53e3hwnd,x,y,h,w)\u5728\u7236\u7a97\u53e3\u5185\u90e8,\u7531miniblink\u521b\u5efa\u4e00\u4e2a\u7f51\u9875\u7a97\u53e3\uff1b\r\n\r\n \u200b\t\u9700\u8981\u5173\u8054\u5904\u7406\u7236\u7a97\u53e3\u4e0e\u672c\u7a97\u53e3\u6d88\u606f\u6d41\u7a0b\uff0c\u4e3b\u8981\u4e3a\u9000\u51fa\u548c\u8c03\u6574\u5927\u5c0f\u7684\u540c\u6b65\u3002\r\n\r\n3. WebView\r\n \tWebView.bind(\u7236\u7a97\u53e3hwnd,x,y,w,h)\u5728\u4e00\u4e2a\u5df2\u7ecf\u521b\u5efa\u7684\u7236\u7a97\u53e3hwnd\u4e0a\u7ed1\u5b9a\u4e00\u4e2a\u7f51\u9875\u89c6\u56fe\uff1b\r\n\r\n \u200b\t\u9700\u8981\u5904\u7406\u7236\u7a97\u53e3\u7684\u6d88\u606f\u6d41\u7a0b\uff0c\u4ee5\u53ca\u81ea\u8eab\u7684\u79bb\u5c4f\u7ed8\u5236\u3002\r\n\r\n \r\n\r\n## \u7a97\u53e3\u6d88\u606f\u5206\u53d1\r\n\r\n\u4e09\u79cd\u6d88\u606f\u8bfb\u53d6\u5206\u53d1\u5faa\u73af\uff1aWke.runMessageLoop()\u3001win32gui.PumpMessages()\u3001wkePumpMessages(block)\t\r\n\r\n\u81ea\u5b9a\u4e49\u6d88\u606f\u5206\u53d1\u5faa\u73af\u65f6\u53ef\u4ee5\u53c2\u8003wkePumpMessages\u7684\u4e24\u79cd\u5206\u53d1\u5faa\u73af\u3002\r\n\r\n\u963b\u585e\u5f0f\r\n\r\n```python\r\nwhile True:\r\n res = windll.user32.GetMessageA(byref(msg), None, 0, 0)\r\n if res != 0:\r\n windll.user32.TranslateMessage(byref(msg))\r\n windll.user32.DispatchMessageA(byref(msg))\r\n elif res == 0:\r\n windll.user32.TranslateMessage(byref(msg))\r\n windll.user32.DispatchMessageA(byref(msg))\r\n break\r\n else:\r\n raise RuntimeError(f\"GetMessage {res}\")\r\n```\r\n\r\n\u975e\u963b\u585e\u5f0f\r\n\r\n```python\r\nwhile True:\r\n res = windll.user32.PeekMessageA(byref(msg), None,0, 0, 1)\r\n if res != 0:\r\n windll.user32.TranslateMessage(byref(msg))\r\n windll.user32.DispatchMessageA(byref(msg))\r\n if msg.message in[WM_QUIT]: \r\n break\r\n else:\r\n time.sleep(0.05)\r\n```\r\n\r\n\r\n\r\n## \u7a97\u53e3\u6d88\u606f\u5904\u7406\r\n\r\n*\u5f53WebView/WebWindow\u7ed1\u5b9a\u5728\u7236\u7a97\u53e3\u4e0b\u65f6,\u9700\u8981\u4fee\u6539\u7236\u7a97\u53e3\u7684\u6d88\u606f\u5904\u7406\u51fd\u6570,\u5b9e\u73b0WebView/WebWindow\u5b50\u7a97\u53e3\u7684\u6d88\u606f\u5904\u7406\u8fc7\u7a0b\u3002*\r\n\r\nwkeWin32\u7684**HwndMsgAdapter**\u4f7f\u7528\u81ea\u8eab\u7684\u6d88\u606f\u5904\u7406\u6d41\u7a0b\u66ff\u6362\u6307\u5b9a\u7236\u7a97\u53e3\u7684\u6d88\u606f\u5904\u7406\uff0c\u63a5\u53d7\u5916\u90e8\u6ce8\u518c\u7684python\u51fd\u6570\u5904\u7406\u6307\u5b9a\u7684\u6d88\u606f\u3002\r\n\r\n\u66ff\u6362\u540e\u5bf9\u4e8e\u5df2\u7ecf\u6ce8\u518c\u7684\u6d88\u606f,\u4f7f\u7528\u6ce8\u518c\u51fd\u6570\u6765\u54cd\u5e94,\u5982\u679c\u51fd\u6570\u8fd4\u56deNone,\u5219\u7ee7\u7eed\u8c03\u7528\u7236\u7a97\u53e3\u7684\u9ed8\u8ba4\u6d88\u606f\u5904\u7406\u6d41\u7a0b,\u82e5\u4e0d\u4e3aNone\u5219\u4e0d\u8c03\u7528;\u5bf9\u4e8e\u6ca1\u6ce8\u518c\u7684\u6d88\u606f\u5219\u4f7f\u7528\u7236\u7a97\u53e3\u7684\u9ed8\u8ba4\u6d88\u606f\u5904\u7406\u6d41\u7a0b\u3002\r\n\r\n\u6ce8\u518c\u7684\u6d88\u606f\u54cd\u5e94\u51fd\u6570\u53ef\u4ee5\u67091~5\u4e2a\u53c2\u6570,\u5982\u4e0b:\r\n\r\n| Arg1 | Arg2 | Arg3 | Arg4 | Arg5 |\r\n| :-----: | :----: | :----: | :----: | :----: |\r\n| webview | hwnd | msg | wParam | lParam |\r\n| self | hwnd | msg | wParam | lParam |\r\n| hwnd | msg | wParam | lParam | |\r\n| hwnd | wParam | lParam | | |\r\n| wParam | lParam | | | |\r\n| self | | | | |\r\n| hwnd | | | | |\r\n\r\nHwndMsgAdapter\u7684\u6d88\u606f\u5904\u7406\u6d41\u7a0b\u8c03\u7528\u6ce8\u518c\u7684\u6d88\u606f\u54cd\u5e94\u51fd\u6570\u65f6:\r\n\r\n- \u53c2\u6570hwnd/msg/wParam/lParam \u4f7f\u7528\u7236\u7a97\u53e3\u7684\u5904\u7406\u6d41\u7a0b\u7684\u53e5\u67c4/\u6d88\u606f/\u53c2\u6570\u5e26\u5165\r\n- \u67095\u4e2a\u53c2\u6570\u65f6\u7b2c\u4e00\u4e2a\u53c2\u6570\u540d\u4e3aself\u6216webview,self\u5219\u5bf9\u5e94HwndProcAdapter\u7c7b\u5b9e\u4f8b\u5e26\u5165,webview\u5bf9\u5e94HwndProcAdapter\u7c7b\u5b9e\u4f8b\u7684webview\u5c5e\u6027\u5e26\u5165\r\n- \u67091\u4e2a\u53c2\u6570\u65f6\u540c\u4e0a,\u53c2\u6570\u540d\u4e3a\u5176\u4ed6\u65f6,\u4ee5\u6d88\u606f\u7a97\u53e3\u53e5\u67c4hwnd\u5e26\u5165\r\n\r\nExample:\r\n\r\n```python\r\n\tx,y,w,h = 0,0,640,480\r\n hwnd = wkeCreateWindow('Window',x,y,w,h)\r\n webview.build(hwnd,x,y,w,h) \r\n\r\n a = HwndMsgAdapter()\r\n def wkeMsgProcQuit(webview,hwnd,msg,wParam,lParam):\r\n win32gui.PostQuitMessage(0)\r\n return \r\n a.registerMsgProc(WM_SIZE,wkeMsgProcResize)\r\n a.registerMsgProc(WM_DESTROY,wkeMsgProcQuit)\r\n a.attach(hwnd,webview)\r\n webview.loadURL(\"http://192.168.1.1\")\r\n ....\r\n```\r\n\r\n***\u9700\u8981\u6ce8\u610f\u7a97\uff1a\u66ff\u6362\u6d88\u606f\u5904\u7406\u51fd\u6570\u4e0e\u6d88\u606f\u5904\u7406\u5faa\u73af\u4e4b\u95f4\u7684\u7a7f\u63d2wke\u7684\u67d0\u4e9b\u7a97\u4f53\u63a7\u5236\u51fd\u6570\u53ef\u80fd\u5bfc\u81f4\u95ee\u9898\uff01***\r\n\r\n## \u4e8b\u4ef6WkeEvent\r\n\r\n*Wke\u5173\u4e8ewebview\u7684\u4e8b\u4ef6\u7ba1\u7406\u662f\u57fa\u4e8eWebView\uff0c\u4e00\u4e2aWebView\u5bf9\u8c61\u7684\u6253\u5f00/\u5173\u95ed/\u52a0\u8f7d/\u7ed8\u5236\u7b49\u4e00\u7cfb\u5217\u4e8b\u4ef6\u90fd\u4f1a\u89e6\u53d1\u6267\u884c\u5176\u4e8b\u4ef6\u54cd\u5e94\u51fd\u6570\u3002*\r\n\r\n**WkeEvent\u4ee5\u3010webview\u7684id\u3011\u3010\u4e8b\u4ef6\u540d\u79f0\u7684id\u3011 \u4e3a\u4e8c\u5143\u7ed3\u6784\uff0c\u7ba1\u7406\u4e8b\u4ef6\u54cd\u5e94\u51fd\u6570\u53ca\u5176\u4e0a\u4e0b\u6587\u3002**\r\n\r\n### \u6ce8\u518c\u4e8b\u4ef6\u5904\u7406\u51fd\u6570onXXXX(webview,func,param) \r\n\r\n1. \u200b\t\t\u63a5\u53d7XXX\u4e8b\u4ef6\u5904\u7406\u7684\u7f51\u9875\u5bf9\u8c61webview\r\n2. \u200b\t\tXXX\u4e8b\u4ef6\u5904\u7406\u51fd\u6570func\r\n3. \u200b\t\t\u6ce8\u518c\u524d\u548c\u8c03\u7528\u540e\u7684\u8d2f\u7a7f\u53c2\u6570param\t\t\r\n\r\n### \u4e8b\u4ef6\u5904\u7406\u51fd\u6570func(context,*args,**kwargs)\r\n\r\n- \u200b\t\t\u7ecfWkeEvent\u7684\u7ffb\u8bd1\uff0c\u4f20\u9012\u7ed9\u4e8b\u4ef6\u54cd\u5e94\u51fd\u6570\u7684\u4e0a\u4e0b\u6587context\u662f\u4e2a\u5b57\u5178\uff0c\u5982\u4e0b\uff1a\r\n\r\n \u200b\t\tcontext = {\"id\":eventid,\"param\":param,\"func\":func,\"webview\":webview,\"id\":webview.cId,\"event\":event}\r\n\r\n- \u200b\t\tparam\u662f\u6ce8\u518c\u56de\u8c03\u51fd\u6570\u65f6OnXXX(func,param)\u7ed1\u5b9a\u7684\u4efb\u610fpython object\u5bf9\u8c61\uff0cfunc\u662f\u7ed1\u5b9a\u7684python\u56de\u8c03\u51fd\u6570\r\n\r\n- \u200b\t\t\u4e0d\u540c\u7684\u4e8b\u4ef6\u6709\u7279\u5b9a\u7684\u6269\u5c55\u53c2\u6570\uff0c\u90fd\u5199\u5728kwargs\u4e2d\uff0c\u4f8b\u5982Alert\u4e8b\u4ef6\u4e2d\u901a\u77e5\u6d88\u606f\u5c31\u5728kwargs[\"msg\"]\u4e2d\r\n\r\n\r\nExample:\r\n\r\n```python\r\n#//python \u4e8b\u4ef6\u54cd\u5e94\u51fd\u6570void OnAlertEvent(context:dict,kwargs={msg:str}) \r\n#/*typedef void(WKE_CALL_TYPE*wkeAlertBoxCallback)(wkeWebView webView, void* param, const wkeString msg);*/\r\n# OnAlertCallback\u56de\u8c03\u51fd\u6570\u6267\u884c\u65f6\u5305\u542b: kwargs[\"msg\"]\r\ndef main():\r\n\t\r\n Wke.setCookieAndStagePath(cookie=f'{father_folder }/build/cookie.dat',localStage=f'{father_folder }/build/LocalStage')\r\n webview = WebWindow()\r\n webview.create(0,0,0,800,600)\r\n\r\n def OnAlertEvent(context,*args,**kwargs):\r\n param = context[\"param\"]\r\n print(f\"{str(param)} \\nargs:{pformat(args)}\\nkwargs:{pformat(kwargs)}\\n=======================\\n\")\r\n msg = kwargs[\"msg\"]\r\n windowTitle = \"\"\r\n result = win32gui.MessageBox(0, msg, windowTitle, win32con.MB_OK)\r\n return result\r\n\r\n def OnCloseEvent(context,*args,**kwargs):\r\n win32gui.PostQuitMessage(0)\r\n return True\r\n\r\n webview.onAlertBox(OnAlertEvent,param='Alert')\r\n webview.onWindowClosing(OnCloseEvent,param='App Quit')\r\n #webview.loadURL('https://www.w3school.com.cn/tiy/t.asp?f=jsck_alert_2')\r\n webview.loadFile(f'{father_folder}/res/testdata/alert.html')\r\n \r\n webview.showWindow(True)\r\n Wke.runMessageLoop()\r\n```\r\n\r\nWebview\u7ed1\u5b9a\u4e86\u4e00\u7cfb\u5217\u4e8b\u4ef6\u56de\u8c03\u51fd\u6570\u6ce8\u518c\u65b9\u6cd5\uff0c\u548c\u4f7f\u7528\u5168\u5c40Wke.event\u7ba1\u7406\u5668\u6ce8\u518c\u7b49\u4ef7:\r\n\r\n```python\r\nWke.event.OnPaintEvent(webview,param,*args,**kwargs)\r\nwebview.OnPaintEvent(param,*args,**kwargs)\r\n```\r\n\r\nunittest/testWebViewOnEvent.py\u68c0\u67e5WkeEvent\u6240\u6709\u4e8b\u4ef6\u662f\u5426\u5728WebView\u90fd\u6709\u5bf9\u5e94\u7684\u7ed1\u5b9a\u5b9e\u73b0\uff0c\u5e76\u751f\u6210\u6240\u9700\u8981\u7684\u5b9e\u73b0\u7ffb\u8bd1\u4ee3\u7801\u3002\r\n\r\n### Javascript \u6269\u5c55\r\n\r\n\u9759\u6001\u7c7b\u51fd\u6570:Wke.extend(func,name,param):\r\n\r\n\u4f7f\u7528\u4e00\u4e2a\u6307\u5b9a\u7684python\u51fd\u6570\u4f5c\u4e3a\u6269\u5c55\u7684js\u51fd\u6570\r\n\r\nExample:\r\n\r\n```python\r\n webview = WebWindow()\r\n webview.create(0,0,0,800,600)\r\n \r\n def pyAction(**kwargs):\r\n es=kwargs['es']\r\n context =kwargs['param']\r\n webview = context\r\n arg_count=Wke.jsArgCount(es)\r\n val_ls=Wke.getJsArgs(es,arg_count)\r\n webview.runJsCode('alert(\"jsCallpy'+str(val_ls)+'\")')\r\n return\r\n \r\n Wke.extend(pyAction,'jsCallpy', param=webview)\r\n```\r\n\r\n \u5728html/js \u4e2d\u8c03\u7528\r\n\r\n```html\r\n<button onclick=\"jsCallpy('jsCallpy', 666)\" style='margin-right: 20px;cursor: pointer;'>jsCallpy</button>\r\n```\r\n\r\n## Javascript \u96c6\u6210\r\n\r\nWebView/WebWindows\u7684runJsCode/runJsFile/runJsFunc\u65b9\u6cd5\u652f\u6301Python\u7aef\u5728\u7f51\u9875\u5bf9\u8c61\u4e2d\u8fd0\u884cjs\u4ee3\u7801\u3002\r\n\r\n## \u5176\u5b83WkeWin32\r\n\r\nWkeWin32\u5305\u542b\u4e86Win32\u76f8\u5173\u4e0b\u9762\u7684\u8f85\u52a9\u65b9\u6cd5\uff1a\r\n\r\nwkeSetIcon/wkeCreateWindow/wkeCreateTransparentWindow/wkeSetWindowLongHook/wkeGetWindowLongHook \u7b49\u65b9\u6cd5;\r\n\r\n\u5b9a\u65f6\u7c7bWkeTimer/\u622a\u5c4f\u7c7bWkeSnapShot\r\n\r\n# \u63d2\u4ef6\u652f\u6301\r\n\r\nMiniblink supports NPAPI plugins.\r\n\r\n\u672a\u9a8c\u8bc1\r\n\r\n# \u79bb\u5c4f\u6e32\u67d3\r\n\r\nWebView.bind(\u7236\u7a97\u53e3hwnd,x,y,w,h)\u5728\u4e00\u4e2a\u5df2\u7ecf\u521b\u5efa\u7684\u7236\u7a97\u53e3hwnd\u4e0a\u7ed1\u5b9a\u4e00\u4e2a\u7f51\u9875\u89c6\u56fe\uff0c\u7136\u540e\u989d\u5916\u7684\u5904\u7406\u7236\u7a97\u53e3\u7684\u6d88\u606f\uff0c\u4ee5\u53ca\u7236\u7a97\u53e3\u5230\u7f51\u9875\u89c6\u56fe\u7684\u7ed8\u5236\u3002\r\n\r\n\u53c2\u89c1wkeWin32ProcMsg\u4e2dWebViewWithProcHwnd\u548cexample/bindWebview.py\r\n\r\n\r\n\r\n# \u53d1\u5e03\r\n\r\n## pyinstaller\r\n\r\n(Pyinstaller>=6.0.0 )\r\n\r\n- \u5728Pyinstaller\u6253\u5305 one dir\uff08-D \u76ee\u5f55\u6a21\u5f0f\uff09\u65f6\uff0c\u9664\u53ef\u6267\u884c\u6587\u4ef6\u5916\uff0c\u5176\u4f59\u6587\u4ef6\u90fd\u5c06\u88ab\u8f6c\u79fb\u5230 _internal \u6587\u4ef6\u5939\r\n\r\n \u5373Package\u6839\u76ee\u5f55\r\n\r\n- \u5728Pyinstaller\u6253\u5305 one file \uff08-F \u6587\u4ef6\u6a21\u5f0f\uff09\u65f6\uff0c\u9664\u53ef\u6267\u884c\u6587\u4ef6\u5916\uff0c\u5176\u4f59\u6587\u4ef6\u90fd\u5c06\u88ab\u8f6c\u79fb\u5230\u4e00\u4e2a\u4e34\u65f6\u6587\u4ef6\u5939\r\n\r\n \u5373Package\u6839\u76ee\u5f55\r\n\r\n- \u5728Python\u89e3\u91ca\u5668\u6a21\u5f0f\u4e0b,\u4ee5Lib\\site-packages\r\n\r\n \u4ee5\u6b64\u4e3aPackage\u7684\u6839\u76ee\u5f55\r\n\r\n\r\n\r\n# \u5176\u4ed6\u95ee\u9898\r\n\r\n## Ctypes\u6570\u636e\u7c7b\u578b\r\n\r\n\u53c2\u89c1prepare.py.translate()\u4e0ewke.h.json\r\n\r\n## Alert/Prompt/Confirm\r\n\r\nMinibilink\u652f\u6301Alert\u548cConfirm,\u4f46\u662fPrompt\u6ca1\u5b9e\u73b0\u3002\r\n\r\n\u53ef\u4ee5\u4f7f\u7528wkeEvent\u7684\u56de\u8c03\u51fd\u6570\u989d\u5916\u5b9e\u73b0\u76f8\u5e94\u7684GUI\u53ca\u5176\u8fd4\u56de\u503c\u63a7\u5236\uff0c\u53c2\u89c1examples.\r\n\r\n## PromptBoxCallback\u7684Py\u5f62\u53c2\u548c\u8fd4\u56de\u503c\r\n\r\n\u6b63\u5e38\u60c5\u51b5\u4e0b\r\n\r\n```\r\ntypedef bool(WKE_CALL_TYPE*wkePromptBoxCallback)(wkeWebView webView, void* param, const wkeString msg, const wkeString defaultResult, wkeString result);\r\n<<=>>\r\nCFUNCTYPE(c_bool,_LRESULT,c_void_p,c_char_p,c_char_p,c_void_p)\r\n```\r\n\r\n\u200b \u539f\u56de\u8c03\u51fd\u6570\u8fd4\u56de\u503c\u4e3ac_bool,\u4e3a\u4fdd\u6301\u5f62\u53c2\u5f62\u5f0f\u4e00\u81f4,\u4e0d\u505a\u6309\u5f15\u7528\u4f20\u53c2\u6570\u5e26\u51fa\u8fd4\u56de\u503c,\u53d6\u6d88\u5f62\u53c2result,\u800c\u662fpython\u7684\u8fd4\u56de\u503c\u3002\r\n\r\n\u200b \u5b9e\u9645python\u56de\u8c03\u51fd\u6570\u8fd4\u56de\u503c\u4e3aStr(\u6709\u5b57\u7b26\u4e32\u786e\u5b9a\u8f93\u5165)/None(\u53d6\u6d88\u8f93\u5165)\r\n\r\n## wkeGetString/wkeSetString/String/StingW\r\n\r\nMiniblink\u6587\u6863\u4e2dString\u5bf9\u5e94utf8*\u800cStringW\u5bf9\u5e94utf16*\r\n\r\nwkeEvent.py\u4e2d32\u4f4d\u4e0bwkeGetStringW(str)\u8fd0\u884c\u6b63\u5e38,\u4f46\u662f64\u4f4d\u4f1ac\u51fd\u6570\u5185\u90e8\u8bfb\u5f02\u5e38\r\n\r\n\u73b0\u5728\u9ed8\u8ba4wkeString\u5168\u90e8\u662futf8\uff0c\u6539\u4e3awkeGetString(str),\u7136\u540e\u505abinary->str\u7684\u89e3\u7801\r\n\r\n## wkeString\u7684Ctypes\u53c2\u6570\u7c7b\u578b\r\n\r\n\u5c06\u53ea\u8bfbwkeString \u5168\u7ffb\u8bd1\u4e3ac_char_p,\u65b9\u4fbfctypes\u81ea\u52a8\u8f6c\u6362\u5b57\u7b26\u4e32\u3002\r\n\r\n\u5982\u679c\u9700\u8981\u5199\u5165wkeString,\u5c31\u7ffb\u8bd1\u4e3ac_void_p (c_char_p\u81ea\u52a8\u7ffb\u8bd1\u4e3aNone)\r\n\r\n```\r\n#wkeString:c_void_p,text:str\r\nutf8 = text.encode(encoding)\r\nl = len(utf8)\r\nmb.wkeSetString(cast(wkeString,c_char_p),utf8,l)\r\n```\r\n\r\nwkePromptBoxCallback\u7684\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u4e3awkeString,\u9700\u8981\u4f5c\u4e3a\u4f20\u53c2\u8fd4\u56de,\u586b\u5165\u5b57\u7b26\u4e32\u3002\u6240\u4ee5wkeString\u7ffb\u6210c_void_p\r\n\r\n\r\n\r\n# TODO\r\n\r\nWke/WebView\u7684job/request\u6709\u4e9b\u5730\u65b9\u672a\u4fee\u8ba2\u9a8c\u8bc1\r\n\r\n\u4e0b\u8f7d/\u63d2\u4ef6/\u901a\u4fe1\u4e8b\u4ef6\u56de\u8c03 \u6682\u90fd\u672a\u9a8c\u8bc1\r\n\r\nRunJs\u9a8c\u8bc1\u4e86\u53c2\u6570\u529f\u80fd\u6b63\u5e38,\u4f46\u662f\u8fd4\u56de\u503c\u603b\u662fNone\r\n\r\n\r\n\r\n\r\n# [Contact Us](mailto://wyh917@163.com)\r\n\r\n",
"bugtrack_url": null,
"license": null,
"summary": "A python binding of Miniblink",
"version": "0.1.17",
"project_urls": {
"Bug Tracker": "https://github.com/StoneFlaw/PyWkeMiniblink/issues",
"Documentation": "https://pywkeminiblink.readthedocs.io/zh-cn/latest/",
"Homepage": "https://pypi.org/project/WkeMiniblink/",
"Source Code": "https://github.com/StoneFlaw/PyWkeMiniblink"
},
"split_keywords": [
"miniblink",
"wke",
"webbrowser"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "ae316eeb81a346511dd14d28f1dc51211cf7a585ed01c5a9ae2c16d095e603e0",
"md5": "4eeb26c4e7e565efbc8d9a251c44bcd9",
"sha256": "6c9b8c1488fe850b142f6d8871473a729fa8dde5e979577445e121324fa998f8"
},
"downloads": -1,
"filename": "WkeMiniblink-0.1.17-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4eeb26c4e7e565efbc8d9a251c44bcd9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 31144650,
"upload_time": "2025-07-09T09:27:05",
"upload_time_iso_8601": "2025-07-09T09:27:05.564133Z",
"url": "https://files.pythonhosted.org/packages/ae/31/6eeb81a346511dd14d28f1dc51211cf7a585ed01c5a9ae2c16d095e603e0/WkeMiniblink-0.1.17-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-09 09:27:05",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "StoneFlaw",
"github_project": "PyWkeMiniblink",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "Pywin32",
"specs": []
}
],
"lcname": "wkeminiblink"
}