Repository navigation
Releases: xiaosuawa/QtWebView
Release list
v0.6.0rc10
v0.6.0rc10
⚠️ Release Candidate — API may still change before the final v0.6.0.
Reworks the transparent host window behind the WebView. rc9 and earlier faked
transparency with a WS_EX_LAYERED window kept alive by UpdateLayeredWindow,
GDI DIB sections, WM_SIZE throttling timers and WM_DWMCOMPOSITIONCHANGED
handling. That whole ctypes/GDI machinery is gone, replaced by a Qt-native
DirectComposition path. Visible behaviour is unchanged — same transparency, same
resize handling, fewer moving parts.
♻️ Rework
_AnchorWindow→ QRhi Direct3D 11 transparent swapchain. The host is now a
QWindowwith aDirect3DSurfaceand an alpha-enabled swapchain
(SurfaceHasPreMulAlpha); Qt builds the full DirectComposition chain and every
frame clears to(0,0,0,0). The DWM composites that transparent surface, so
transparent=Truecontent shows the Qt widgets behind it and the black-edge
flash on resize is absorbed — without any layered-window / GDI hacks or
per-frame timers (the loop only runs on expose/resize).
⚠️ Requirements / Breaking
- Windows transparency now requires PySide6 on Windows 8+. The RHI backend
usesQRhi, which is Qt6-only and — among the Qt6 bindings — exposed only by
PySide6; DirectComposition needs Windows 8+. - Auto fallback. The
QRhiimport is guarded, so
import qtwebview2still succeeds under PyQt6 / PyQt5 / PySide2. On those
bindings the host falls back to an opaque plainQWindow(transparency and
resize-flicker suppression disabled) and logs a warning at construction —
instead of crashing at import. - macOS is unaffected — WKWebView handles transparency itself.
🪶 v0.6.0rc10 更新内容
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
重写了 WebView 背后的透明宿主窗口。rc9 及更早版本用 WS_EX_LAYERED 分层窗口
配合 UpdateLayeredWindow、GDI DIB、WM_SIZE 节流定时器和
WM_DWMCOMPOSITIONCHANGED 处理来伪造透明。这套 ctypes/GDI 机器全部移除,改用
Qt 原生的 DirectComposition 路径。可见行为不变 —— 一样的透明、一样的 resize
处理,但内部零件更少。
♻️ 重构
_AnchorWindow→ QRhi Direct3D 11 透明 swapchain。 宿主现在是带
Direct3DSurface和 alpha swapchain(SurfaceHasPreMulAlpha)的QWindow;
Qt 自动搭好整条 DirectComposition 链,每帧清成(0,0,0,0)。DWM 合成这个透明
表面,于是transparent=True的内容能透出后面的 Qt 控件,resize 时的黑边闪烁
也被吸收 —— 不再需要任何分层窗口/GDI hack 或每帧定时器(渲染循环只在
expose/resize 时跑)。
⚠️ 要求 / 破坏性变更
- Windows 透明现在需要 PySide6 且系统为 Windows 8+。 RHI 后端用到
QRhi,它
是 Qt6 独有、且在 Qt6 各绑定中仅 PySide6 暴露;DirectComposition 需 Windows 8+。 - 自动降级
QRhi导入已加守卫,PyQt6 / PyQt5 / PySide2 下
import qtwebview2仍能成功。这些绑定下宿主退化为不透明的普通QWindow
(透明与 resize 抗闪失效),并在构造时打印一条警告 —— 而不是在导入时崩溃。 - macOS 不受影响 —— 透明由 WKWebView 自身处理。
Full Changelog: v0.6.0rc9...v0.6.0rc10
v0.6.0rc9
v0.6.0rc9
Hotfix on top of rc8.
🐛 Fix
api.call()broken —window.qtwebview.api.call("funcName", ...)threwTypeErrorbecause the Proxy referenced a non-existenttarget.apiinstead of itself. Fixed by capturing the proxy in a variable before assignment.
v0.6.0rc8
v0.6.0rc8
Hotfix on top of rc7.
🐛 Fix
- WebView not properly torn down on quit —
closeEventis only called when the window is closed via the window manager.QApplication.quit()or process exit could skip it, causing the Rust webview to be dropped without flushing localStorage. AddedQApplication.aboutToQuitas a safety net that fires on any exit path.
🪶 v0.6.0rc8
rc7 的热修复。
🐛 修复
- 退出时 WebView 未正确销毁 —
closeEvent仅在窗口管理器关闭时触发,QApplication.quit()或进程退出可能跳过它,导致 Rust webview 未被正确释放、localStorage 数据丢失。新增QApplication.aboutToQuit兜底,保证所有退出路径都能正确清理。
v0.6.0rc7
What's New in v0.6.0rc7
This is likely the last release candidate before v0.6.0 stable.
✨ New Features
- 🧩 Enums —
PageLoadEvent,NewWindowResponse,DragDropEventare now proper PythonEnumtypes (re-exported from wryview). No more magic strings in callbacks. - 🔒
https_scheme(Windows, defaultTrue) — custom protocol pages are now secure contexts by default. Service Workers, Geolocation, Web Crypto all work out of the box. - 📥 Download handlers —
download_started_handler(url, suggested_path) → bool|stranddownload_completed_handler(url, saved_path, success: bool). - 🖱️
context_menus— enable/disable native right-click context menu (Windows). - 🌐
proxy—{"type": "http"|"socks5", "host": "...", "port": "..."}. - 📜
initialization_script— three states: default (injects JS bridge + fullscreen),None(skip all injected scripts),str(custom script). Use with caution — setting toNoneor custom breaks the JS bridge and fullscreen handling. - 🔧
wsgi_port— specify a fixed TCP port forwsgi_scheme="localhost"mode. - 🔍
is_devtools_open()— check if DevTools is currently open. back_forward_gesturesgesture navigation (cross-platform, not macOS only).
⚠️ Breaking Changes
- Callback return types now use enums:
new_window_handler→NewWindowResponse(wasstr)page_loadedsignal →(PageLoadEvent, url)(was(str, str))drag_drop_handler→(DragDropEvent, paths, position)(was(str, ...))
initialization_donesignal no longer carries(success, error_msg)— just().domContentLoadedsignal removed — usepage_loaded(eventPageLoadEvent.Finished) instead.user_data_folderdefault changed to sentinel-based tri-state: omit = auto-generate,None= skip,str= custom path.incognitoanduser_data_folderare now independent —incognitono longer overrides the data directory.
🐛 Fixes
- JS Bridge: error responses no longer misrouted to the wrong pending Promise.
- JS Bridge:
window.qtwebview.api.call("funcName", ...)meta-call now handled in JS, no Python round-trip. web_message_receivedsignal no longer emitted twice for non-JSON IPC messages.- GDI resource leak:
_AnchorWindownow cleans up DIB section, DC, and bitmap on close. - Hide & show: DWM layered surface restored via
WM_SHOWWINDOW(more robust thanshowEvent). closeEventorder documented — child HWND dropped before parent anchor.
📦 Dependencies
- wryview bumped to
~=0.4.0.
🪶 v0.6.0rc7 更新内容
这很可能是 v0.6.0 正式版前的最后一个候选版本。
✨ 新特性
- 🧩 枚举类型 —
PageLoadEvent、NewWindowResponse、DragDropEvent替代了所有魔术字符串(从 wryview 转发)。 - 🔒
https_scheme(Windows,默认True)— 自定义协议页面默认已是安全上下文,Service Worker 等开箱即用。 - 📥 下载回调 —
download_started_handler/download_completed_handler。 - 🖱️
context_menus— 原生右键菜单开关(Windows)。 - 🌐
proxy— 代理配置{"type": "http"|"socks5", "host": "...", "port": "..."}。 - 📜
initialization_script— 三态:默认注入桥接+全屏 /None跳过 / 字符串自定义。设None或自定义会破坏 JS 桥接和全屏,需手动重实现。 - 🔧
wsgi_port— localhost 模式下指定固定端口。 - 🔍
is_devtools_open()— 查询 DevTools 是否打开。 back_forward_gestures手势导航(跨平台,不仅 macOS)。
⚠️ 破坏性变更
- 回调改用枚举:
new_window_handler→NewWindowResponsepage_loaded信号 →(PageLoadEvent, url)drag_drop_handler→(DragDropEvent, paths, position)
initialization_done信号不再携带(success, error_msg)。domContentLoaded信号已移除,用page_loaded(PageLoadEvent.Finished)替代。user_data_folder改为三态(不传=自动生成 /None=跳过 / 字符串=自定义路径)。incognito与user_data_folder解耦——incognito不再覆盖数据目录。
🐛 修复
- JS Bridge:错误响应不再路由到错误的 Promise。
- JS Bridge:
api.call("funcName")元调用改为 JS 侧处理。 web_message_received信号不再重复发射。- _AnchorWindow GDI 泄漏:关闭时正确释放 DIB、DC 和位图。
- 隐藏/恢复:改用
WM_SHOWWINDOW恢复 DWM 分层表面。 closeEvent顺序注释。
📦 依赖
- wryview 升级至
~=0.4.0。
v0.6.0rc6
⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
🐛 Fixes / 修复
-
hide/show 后无法点击 — click-through after hide/show cycle。 窗口隐藏再显示后 DWM 丢弃了 layered surface(大小未变,不触发
WM_SIZE),导致全区域 alpha=0 点击穿透。修复:_AnchorWindow.showEvent中立即调用_fill_layered()重建 alpha=1 表面。After hiding and re-showing the window, the DWM discards the layered surface. No
WM_SIZEis sent (the size didn't change), so the entire surface stays alpha=0 and clicks pass through. Fixed by calling_fill_layered()in_AnchorWindow.showEventto immediately rebuild the alpha=1 surface. -
RDP / DWM 重启后点击穿透 — click-through after RDP disconnect or DWM restart。 远程桌面连接/断开、DWM 重启、主题切换等场景下 layered surface 可能被丢弃。修复:
nativeEvent中新增WM_DWMCOMPOSITIONCHANGED(0x031E)处理,立即重建表面。The layered surface may be discarded after RDP connect/disconnect, DWM restart, or theme toggle. Fixed by handling
WM_DWMCOMPOSITIONCHANGED(0x031E) innativeEventand rebuilding the surface immediately. -
全屏窗口遗失 — lost fullscreen window。 全屏状态下点击主窗口后全屏窗口可能被盖在后面找不到。修复:全屏窗口去掉了
Tool标志(有任务栏入口,可被找到),showEvent中自动raise_()+activateWindow()。全屏窗口跟随主窗口 hide/show 联动。The fullscreen window could get lost behind the main window. Fixed by removing the
Toolflag (so it appears in the taskbar), auto-raising it when the main window is shown, and syncing hide/show with the main window. -
全屏
FramelessWindowHint— 全屏窗口不再使用Tool标志,改用FramelessWindowHint。
🔧 Improvements / 改进
-
日志增强 Enhanced logging。 所有日志消息现在包含 widget 对象引用
[<QtWebViewWidget 0x...>],多 webview 实例时可区分来源。新增关键节点日志:WebView 创建模式/平台/耗时、pending calls 刷新、JS API 调用、WSGI 请求、关闭。All log messages now include the widget object reference
[<QtWebViewWidget 0x...>]for multi-webview traceability. Added log points: WebView creation mode/platform/timing, pending call flush, JS API calls, WSGI requests, close.
Full Changelog: https://github.com/xiaosuawa/QtWebView/commits/v0.6.0rc6
v0.6.0rc5
⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
🐛 Fixes / 修复
-
Windows resize black-edge flicker — Windows resize 黑边闪烁。 窗口缩放时 WebView 边缘出现短暂黑色闪烁。根因:DWM layered surface 扩展后新区域 alpha=0,且
createWindowContainer阻止了_AnchorWindow的paintEvent触发。修复方案:_AnchorWindow监听WM_SIZE/WM_EXITSIZEMOVE,直接调用 Win32UpdateLayeredWindowAPI 提交 per-pixel alpha=1 的 32-bit BGRA 背景层 bitmap,绕过 Qt 的 paint 系统。调用频率节流至 ~30fps 避免 DWM 重合成导致 WebView 内容闪烁。缓存 DIB section 避免每次 resize 重建 GDI 对象。The WebView showed a brief black flash at the edges during window resize. Root cause: the DWM layered surface defaults new areas to alpha=0, and
createWindowContainersuppresses_AnchorWindow'spaintEvent. Fix:_AnchorWindowlistens forWM_SIZE/WM_EXITSIZEMOVEand calls Win32UpdateLayeredWindowdirectly to submit a per-pixel alpha=1 32-bit BGRA background bitmap — bypassing Qt's paint machinery entirely. Calls are throttled to ~30 fps to prevent DWM re-composition flicker of the WebView content. The DIB section is cached to avoid GDI object churn.
🔧 Internal / 内部重构
-
模块拆分 Module split。
widget.py(~960 行)拆为三个文件:_bridge.py(JS Bridge:Signals、DictJsBridge、JS 脚本)、_anchor.py(_AnchorWindow:Windows layered surface resize 修复)、widget.py(QtWebViewWidget:~660 行)。下划线前缀表示内部模块,不暴露给用户。widget.py(~960 lines) split into three modules:_bridge.py(JS Bridge: Signals, DictJsBridge, JS payloads),_anchor.py(_AnchorWindow: Windows layered surface resize fix),widget.py(QtWebViewWidget: ~660 lines). Underscore prefix denotes internal modules — not part of the public API.
Full Changelog: v0.6.0rc4...v0.6.0rc5
v0.6.0rc4
⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
修复mac上启动时webview错位的问题
Fix the issue of WebView misalignment on startup on Mac
Full Changelog: v0.6.0rc3...v0.6.0rc4
v0.6.0rc3
⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
✨ New / 新增
- Fullscreen API — 新增
fullscreen_handler参数,通过注入 JS 拦截
requestFullscreen/exitFullscreen。默认实现将 webview 容器 reparent
到独立的全屏 QWidget(仅 anchor 模式)。 wsgi_executor支持传入Executor— 除了int(线程数),现在也可以
传入concurrent.futures.Executor实例,方便共享线程池。new_window_handler默认值 — 默认用系统浏览器打开 URL 并返回'deny',
不再需要手动提供。_resize_webview()— widget resize 时自动同步 webview 尺寸。
🐛 Fixes / 修复
- Windows 点击穿透 — 修复
_AnchorWindow在 Windows 上使用
WA_TranslucentBackground导致的交互失效:createWindowContainer嵌入后
paintEvent不再触发,扩展区域的 alpha-1 填充缺失,DWM hit-test 失败,
点击穿透到桌面。修复方案:Windows 上去掉WA_TranslucentBackground。
macOS 保留(无 per-pixel hit-test 问题)。
🔧 Improvements / 改进
- WSGI localhost 模式重构为通过线程池派发请求,与 custom protocol 模式
共享同一个wsgi_executor。 - 移除
closeEvent中不必要的_wsgi_executor.shutdown(),避免破坏
用户传入的共享 executor。 - 导入整理,移除未使用的
QPainter/QColor。
Full Changelog: v0.6.0rc2...v0.6.0rc3
v0.6.0rc2
⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
🏗️ Architecture / 架构变更
WebView 嵌入方式从直接子窗口改为独立锚点窗口 + fromWinId + createWindowContainer。
The WebView is now hosted inside an independent anchor QWindow (floating, frameless, tool window) rather than as a direct native child of the Qt widget. The anchor is wrapped via QWindow.fromWinId() + createWindowContainer(), so Qt manages geometry automatically — no manual set_bounds, no resizeEvent syncing.
核心收益 / Key benefit:
-
锚点窗口独立于 Qt widget 树 —— 父窗口 close/show 不会销毁 WebView。托盘应用不再需要担心 WebView 消失。
The anchor window is independent of the Qt widget tree — parent window close/show cycles don't kill the WebView. Tray apps just work. -
wry
build()自动管理大小 ——as_child=False让 wry 通过 WM_SIZE 子类化自动填满锚点,无需手动调用set_bounds。
as_child=Falselets wry'sbuild()auto-fill the anchor via WM_SIZE subclassing — no manualset_bounds.
✨ New / 新增
native_child: bool = False— 设为True恢复旧行为(WebView 作为 widget 的直接原生子窗口)。默认False使用新锚点方案。
Set toTrueto restore the old behaviour (WebView as a direct native child of the widget). DefaultFalseuses the new anchor scheme.
🗑️ Removed / 移除
- 不再需要
WA_NativeWindow(默认路径下)。锚点窗口自己管理原生句柄。
WA_NativeWindowno longer needed in the default path. The anchor window manages its own native handle.
📝 Docs / 文档
- README 新增 System Tray / Hide & Show 章节(中英双语),说明
closeEvent中应使用event.ignore()+hide()而非默认close()。
Added System Tray / Hide & Show section (EN & ZH) explainingevent.ignore()+hide()instead ofclose()in tray apps.
📦 Dependencies / 依赖
- wryview
~=0.2.0→~=0.3.0
Full Changelog: v0.6.0rc1...v0.6.0rc2
v0.6.0rc1
⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。
🔄 Complete rewrite of the backend — pythonnet/.NET replaced by wryview (Rust/PyO3).
🔄 后端完全重写 — pythonnet/.NET 替换为 wryview (Rust/PyO3)。
💥 Breaking Changes / 破坏性变更
Backend switched to wryview v0.2.0 — a Rust/PyO3 binding for wry, the WebView engine used by Tauri. The old pythonnet + .NET CLR + WebView2 WinForms stack is fully removed.
后端切换为 wryview v0.2.0 — Rust/PyO3 的 wry 绑定。旧的 pythonnet + .NET CLR + WebView2 WinForms 技术栈已完全移除。
| v0.5.x | v0.6.0 |
|---|---|
QtWebView2Widget |
QtWebViewWidget (旧名保留为 deprecated 别名) |
QtWebView2ApiBridge |
QtWebViewSignals |
QtWebView2JsBridge |
QtWebViewJsBridge |
handle_new_window=True/False |
new_window_handler=lambda url: "allow"/"deny" |
wsgi_host_name="myapp.local" |
wsgi_scheme="qtwebview" |
no_local_storage=True |
incognito=True |
context_menus |
已移除 |
fullscreen_support |
已移除(尚未实现) |
browser_executable_folder |
已移除(wry 不支持) |
init_settings_hook |
已移除 |
user_data_folder |
✅ 仍支持 |
wsgi_executor |
✅ 仍支持(线程池大小) |
requires-python >= 3.9 |
>= 3.10(与 wryview 一致) |
所有已删除的旧文件:_dotnet_bridge.py、wsgi_server.py、exceptions.py、utils.py、logger.py、lib/(.NET 程序集)、__pyinstaller__/。
✨ New Features / 新功能
- 🌍 跨平台 — Windows (WebView2)、macOS (WKWebView)、Linux (WebKitGTK)。统一 API。
- ⚡ 更快的启动速度 — 无 .NET CLR
- 🍪 完整的 wry API — Cookie 管理 (
cookies、cookies_for_url、set_cookie、delete_cookie)、DevTools (open_devtools、close_devtools、is_devtools_open)、缩放、打印、拖放、代理、自定义请求头 - 📦 新的构造参数
html— 直接加载 HTML 字符串headers— 自定义 HTTP 请求头(dict 或 list of tuples)navigation_handler— 导航拦截回调(返回 False 阻止)incognito— 无痕模式autoplay— 媒体自动播放javascript_enabled— 启用/禁用 JavaScripthotkeys_zoom— Ctrl+/- 缩放快捷键drag_drop_handler— 拖放事件处理
eval_js(script)— 新的便捷别名,等价于evaluate_js(script)url()— 获取当前页面 URLclose_devtools()— 关闭 DevTools 窗口cookies_for_url(url)— 获取特定 URL 的 cookieset_background_color(r, g, b, a)— 动态设置背景色- JS Bridge 命名统一 — JS 端
window.qtwebview.api和window.qtwebview2均可使用 incognito=True+user_data_folder冲突警告 — 同时设置时输出 warning 日志
🐛 Fixes / 修复
- 修复了
_pending_calls重复声明的问题 - 修复了旧版 README 迁移指南中多处不准确描述
- 修复了 LICENSE 链接中的 GitHub 用户名不一致问题
📦 Packaging / 打包
- 移除
__pyinstaller__/hook(不再需要收集 .NET 程序集) - wryview 的
.pyd/.so由 PyInstaller/Nuitka 自动收集 - 如遇问题,在 PyInstaller 中添加
hiddenimports=['wryview._core']
Full Changelog: v0.5.0...v0.6.0rc1