from PyQt6.QtWebEngineCore import QWebEnginePage, QWebEngineScript, QWebEngineProfile from PyQt6.QtCore import QUrl from PyQt6.QtGui import QDesktopServices class CustomWebPage(QWebEnginePage): """ 自定义网页类,集中约束内置 QtWebEngine 的不合规浏览器行为: 1. 拦截所有外部链接跳转,改用系统默认浏览器打开; 2. 禁用 Ctrl/Meta + 滚轮 及 Ctrl + +/-/0 快捷键的页面缩放 (浏览器式缩放对桌面聊天工具无意义且易误触)。 """ def __init__(self, profile_or_parent=None, parent=None): # P1-03:兼容两种调用 —— 新式 CustomWebPage(profile, parent) 与旧式 CustomWebPage(parent)。 # profile 缺省 None → QtWebEngine 默认 profile;main_window 传入本实例独立 profile。 if isinstance(profile_or_parent, QWebEngineProfile): profile, par = profile_or_parent, parent else: profile, par = None, profile_or_parent if parent is not None: raise TypeError("CustomWebPage(profile, parent) 或 CustomWebPage(parent)") if profile is not None: super().__init__(profile, par) else: super().__init__(par) self._inject_zoom_lock() def _inject_zoom_lock(self): """ 🌟 缩放锁定:通过网页脚本在文档创建阶段(DocumentCreation)注入监听, 使用隔离世界(ApplicationWorld)注入,不污染页面自身逻辑。 原理:Chromium 的 Ctrl+滚轮缩放会先经过页面 wheel 事件的 preventDefault() 判定 —— 页面阻止即取消缩放,这是地图类应用 禁用缩放的官方做法;Ctrl+=/-/0 快捷键同理用 keydown 拦截。 """ script = QWebEngineScript() script.setName("haocode_zoom_lock") script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentCreation) script.setWorldId(QWebEngineScript.ScriptWorldId.ApplicationWorld) script.setRunsOnSubFrames(True) script.setSourceCode(r""" (function () { if (window.__haocodeZoomLocked) return; // 防重复注入 window.__haocodeZoomLocked = true; // 1) Ctrl/Meta + 滚轮 → 阻止缩放 document.addEventListener('wheel', function (e) { if (e.ctrlKey || e.metaKey) { e.preventDefault(); e.stopPropagation(); } }, { passive: false }); // 必须非被动,preventDefault 才有效 // 2) Ctrl + = / + / - / 0 → 阻止缩放快捷键 document.addEventListener('keydown', function (e) { if ((e.ctrlKey || e.metaKey) && ['+', '-', '=', '0'].indexOf(e.key) >= 0) { e.preventDefault(); } }, false); })(); """) self.scripts().insert(script) def acceptNavigationRequest(self, url: QUrl, nav_type, is_main_frame): # 如果是本地文件(我们自己的 index.html),允许加载 if url.scheme() == "file": return True # 如果是外部链接(http/https),用系统浏览器打开 if url.scheme() in ["http", "https"]: print(f"[System]: 在系统浏览器中打开 -> {url.toString()}") QDesktopServices.openUrl(url) return False # 阻止在应用内跳转 # 其他情况(如 javascript:void(0)),允许 return True