解决windows无法嵌入web面板问题

This commit is contained in:
Hector 2025-12-05 16:46:05 +08:00
parent 812e5863cb
commit 9e45efe306

View File

@ -1,5 +1,4 @@

"""
"""
主窗口设置模块
负责主窗口的界面构建和事件绑定
@ -7,22 +6,259 @@
- 停靠窗口设置
- 事件连接和信号处理
"""
import os
WEB_BROWSER_PROCESS_CODE = r"""
import sys
import os
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt5.QtCore import Qt, QUrl, QTimer
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtGui import QKeySequence, QIcon, QPalette, QColor
# 禁用硬件加速
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu --disable-software-rasterizer --disable-gpu-compositing --in-process-gpu"
os.environ["QT_WEBENGINE_DISABLE_GPU"] = "1"
os.environ["QT_OPENGL"] = "software"
# QtWebEngine 导入(环境变量已在 main.py 中配置)
try:
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
WEB_ENGINE_AVAILABLE = True
print("✓ QtWebEngineWidgets 已导入")
except ImportError:
WEB_ENGINE_AVAILABLE = False
QWebEngineView = None
print("⚠️ QtWebEngine 不可用")
class EmbeddedWebBrowser(QWidget):
def __init__(self, parent=None, url="https://www.baidu.com", parent_window_id=0):
super().__init__(parent)
self.setWindowTitle("Web 浏览器")
self.parent_window_id = parent_window_id
self.url = url
# 设置窗口标志 - 如果要嵌入,使用子窗口样式
if parent_window_id > 0:
# 使用 FramelessWindowHint 去除边框,便于嵌入
self.setWindowFlags(Qt.FramelessWindowHint)
else:
self.setWindowFlags(Qt.Window)
self.resize(800, 600)
# 设置背景色
palette = self.palette()
palette.setColor(QPalette.Window, QColor(25, 25, 27))
self.setPalette(palette)
self.setAutoFillBackground(True)
# 创建布局
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
if WEB_ENGINE_AVAILABLE:
# 创建 WebEngine 视图
self.web_view = QWebEngineView()
# 设置样式
self.web_view.setStyleSheet("background-color: #19191b;")
# 禁用硬件加速
settings = self.web_view.settings()
settings.setAttribute(QWebEngineSettings.Accelerated2dCanvasEnabled, False)
settings.setAttribute(QWebEngineSettings.WebGLEnabled, False)
settings.setAttribute(QWebEngineSettings.PluginsEnabled, False)
settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True)
settings.setAttribute(QWebEngineSettings.AutoLoadImages, True)
settings.setAttribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls, True)
# 连接加载信号
self.web_view.loadStarted.connect(self.on_load_started)
self.web_view.loadProgress.connect(self.on_load_progress)
self.web_view.loadFinished.connect(self.on_load_finished)
layout.addWidget(self.web_view)
print("[WebEngine] WebEngine 视图已创建")
# 延迟加载网页,确保窗口完全初始化
QTimer.singleShot(500, lambda: self.load_url(url))
else:
from PyQt5.QtWidgets import QLabel
label = QLabel("QtWebEngine 不可用\n请安装: pip install PyQtWebEngine")
label.setAlignment(Qt.AlignCenter)
label.setStyleSheet("color: white; font-size: 14px;")
layout.addWidget(label)
def on_load_started(self):
print("[WebEngine] 开始加载网页...")
def on_load_progress(self, progress):
if progress % 20 == 0: # 每20%打印一次
print(f"[WebEngine] 加载进度: {progress}%")
def on_load_finished(self, success):
if success:
print("[WebEngine] 网页加载成功")
else:
print("[WebEngine] 网页加载失败")
def load_url(self, url):
if WEB_ENGINE_AVAILABLE and hasattr(self, 'web_view'):
print(f"[WebEngine] 准备加载 URL: {url}")
qurl = QUrl(url)
print(f"[WebEngine] QUrl 有效性: {qurl.isValid()}")
print(f"[WebEngine] QUrl 内容: {qurl.toString()}")
self.web_view.load(qurl)
print(f"[WebEngine] load() 方法已调用")
else:
print(f"[WebEngine] 无法加载 URL - WEB_ENGINE_AVAILABLE={WEB_ENGINE_AVAILABLE}, has_web_view={hasattr(self, 'web_view')}")
def get_native_window_id(self):
return int(self.winId())
def embed_into_parent(self):
if self.parent_window_id > 0:
try:
print(f"[WebEngine] 开始嵌入窗口到父窗口 ID: {self.parent_window_id}")
# Windows 平台使用 win32 API 嵌入窗口
if sys.platform == 'win32':
import ctypes
from ctypes import wintypes
# 获取窗口句柄
hwnd = int(self.winId())
parent_hwnd = self.parent_window_id
print(f"[WebEngine] 子窗口句柄: {hwnd}")
print(f"[WebEngine] 父窗口句柄: {parent_hwnd}")
user32 = ctypes.windll.user32
# 先获取父窗口大小
rect = wintypes.RECT()
user32.GetClientRect(parent_hwnd, ctypes.byref(rect))
width = rect.right - rect.left
height = rect.bottom - rect.top
print(f"[WebEngine] 父窗口大小: {width}x{height}")
# 设置父窗口
result = user32.SetParent(hwnd, parent_hwnd)
print(f"[WebEngine] SetParent 结果: {result}")
# 设置窗口样式为子窗口
GWL_STYLE = -16
WS_CHILD = 0x40000000
WS_VISIBLE = 0x10000000
WS_CLIPCHILDREN = 0x02000000
WS_CLIPSIBLINGS = 0x04000000
old_style = user32.GetWindowLongW(hwnd, GWL_STYLE)
print(f"[WebEngine] 旧窗口样式: {hex(old_style)}")
# 设置为子窗口样式,移除边框和标题栏
new_style = (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
user32.SetWindowLongW(hwnd, GWL_STYLE, new_style)
print(f"[WebEngine] 新窗口样式: {hex(new_style)}")
# 调整窗口位置和大小,填充整个父窗口
SWP_FRAMECHANGED = 0x0020
SWP_SHOWWINDOW = 0x0040
SWP_NOZORDER = 0x0004
result = user32.SetWindowPos(
hwnd,
0, # HWND_TOP
0, 0, # x, y
width, height, # width, height
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOZORDER
)
print(f"[WebEngine] SetWindowPos 结果: {result}")
# 强制刷新窗口
user32.UpdateWindow(hwnd)
user32.InvalidateRect(hwnd, None, True)
print(f"[WebEngine] 已成功嵌入到父窗口 (Windows)")
return True
else:
# 其他平台使用 Qt 的方式
from PyQt5.QtGui import QWindow
parent_window = QWindow.fromWinId(self.parent_window_id)
if parent_window:
self.windowHandle().setParent(parent_window)
print(f"[WebEngine] 已嵌入到父窗口 (Qt): {self.parent_window_id}")
return True
except Exception as e:
print(f"[WebEngine] 嵌入窗口失败: {e}")
import traceback
traceback.print_exc()
return False
def main():
# 设置标准输出编码为 UTF-8避免 Windows GBK 编码问题
if sys.platform == 'win32':
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
print("=" * 60)
print("[WebEngine] 启动独立 WebEngine 进程")
print("=" * 60)
# 创建应用
app = QApplication(sys.argv)
# 从命令行参数获取 URL 和窗口 ID
url = sys.argv[1] if len(sys.argv) > 1 else "https://www.baidu.com"
parent_window_id = int(sys.argv[2]) if len(sys.argv) > 2 else 0
print(f"[WebEngine] 参数:")
print(f" - URL: {url}")
print(f" - 父窗口 ID: {parent_window_id}")
# 创建浏览器窗口
browser = EmbeddedWebBrowser(url=url, parent_window_id=parent_window_id)
# 显示窗口
browser.show()
# 输出窗口 ID 供父进程使用
window_id = browser.get_native_window_id()
print(f"WINDOW_ID:{window_id}")
sys.stdout.flush()
# 等待网页开始加载后再嵌入窗口
if parent_window_id > 0:
# 延迟2秒确保网页已经开始加载和渲染
QTimer.singleShot(10, browser.embed_into_parent)
print("[WebEngine] 进程已就绪")
print("=" * 60)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
"""
import os
import sys
# ==================== 禁用 QtWebEngine 硬件加速 ====================
# 必须在导入 QtWebEngine 之前设置环境变量
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu --disable-software-rasterizer --disable-gpu-compositing --in-process-gpu"
os.environ["QT_WEBENGINE_DISABLE_GPU"] = "1"
os.environ["QT_OPENGL"] = "software"
print("✓ QtWebEngine 硬件加速已禁用,使用软件渲染模式")
# ==================== 结束配置 ====================
from PyQt5.QtGui import QKeySequence, QIcon, QPalette, QColor
# from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction,
QDockWidget, QTreeWidget, QListWidget, QWidget, QVBoxLayout, QTreeWidgetItem,
QLabel, QLineEdit, QFormLayout, QDoubleSpinBox, QScrollArea,
@ -39,7 +275,7 @@ from ui.widgets import (CustomMeta3DWidget, CustomFileView, CustomTreeWidget,
UniversalMessageDialog)
from ui.icon_manager import get_icon_manager, get_icon
import yaml
# import yaml
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QListWidget, QPushButton, QDialogButtonBox, QCheckBox, QLabel, QHBoxLayout
from PyQt5.QtCore import Qt
@ -1516,13 +1752,13 @@ class MainWindow(QMainWindow):
self.createSamplePanelAction.triggered.connect(self.world.info_panel_manager.onCreateSampleInfoPanel)
self.create3DSamplePanelAction.triggered.connect(self.onCreate3DSampleInfoPanel)
#self.webBrowserAction.triggered.connect(self.openWebBrowser_win)
if sys.platform == 'win32':
self.webBrowserAction.triggered.connect(self.openWebBrowser_win)
else:
self.webBrowserAction.triggered.connect(self.openWebBrowser)
def getCreateMenuActions(self):
"""获取所有创建菜单动作的字典 - 供右键菜单使用"""
return {
@ -2307,90 +2543,90 @@ class MainWindow(QMainWindow):
self.bottomDock.setWidget(bottomDockContainer)
self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock)
# # 创建底部停靠控制台
# self.consoleDock = QDockWidget("控制台", self)
# self.consoleDock.setStyleSheet("""
# QDockWidget {
# background-color: #19191b;
# color: #ffffff;
# border: none;
# }
# QDockWidget::title {
# background-color: #19191b;
# padding: 8px 10px;
# border-bottom: none;
# text-align: left;
# font-family: 'Microsoft YaHei', 'Inter', sans-serif;
# font-size: 14px;
# font-weight: 500;
# }
# QDockWidget::close-button {
# background-color: rgba(89, 100, 113, 0.3);
# border: 1px solid rgba(184, 211, 241, 0.2);
# icon-size: 10px;
# border-radius: 2px;
# width: 16px;
# height: 16px;
# right: 6px;
# top: 6px;
# }
# QDockWidget::float-button {
# background-color: rgba(89, 100, 113, 0.3);
# border: 1px solid rgba(184, 211, 241, 0.2);
# icon-size: 10px;
# border-radius: 2px;
# width: 16px;
# height: 16px;
# right: 26px;
# top: 6px;
# }
# QDockWidget::close-button:hover, QDockWidget::float-button:hover {
# background-color: rgba(89, 100, 113, 0.5);
# border: 1px solid rgba(184, 211, 241, 0.3);
# }
# QDockWidget::close-button:pressed, QDockWidget::float-button:pressed {
# background-color: #3067c0;
# border: 1px solid rgba(48, 103, 192, 0.6);
# }
# """)
# self.consoleView = CustomConsoleDockWidget(self.world)
# # 为控制台添加样式
# self.consoleView.setStyleSheet("""
# QTextEdit {
# background-color: #19191b;
# color: #ebebeb;
# border: none;
# font-family: 'Consolas', 'Monaco', 'Microsoft YaHei', monospace;
# font-size: 10px;
# font-weight: 300;
# }
# """)
#
# # 创建包装容器,添加标题下方的分隔线
# consoleDockContainer = QWidget()
# consoleDockContainer.setStyleSheet("QWidget { background-color: #19191b; }")
# consoleDockLayout = QVBoxLayout(consoleDockContainer)
# consoleDockLayout.setContentsMargins(0, 0, 0, 0)
# consoleDockLayout.setSpacing(0)
#
# # 添加带左右间距的分隔线
# consoleSeparator = QFrame()
# consoleSeparator.setFrameShape(QFrame.HLine)
# consoleSeparator.setFrameShadow(QFrame.Plain)
# consoleSeparator.setStyleSheet("""
# QFrame {
# background-color: rgba(77, 116, 189, 0.4);
# max-height: 1px;
# margin-left: 8px;
# margin-right: 8px;
# border: none;
# }
# """)
# consoleDockLayout.addWidget(consoleSeparator)
# consoleDockLayout.addWidget(self.consoleView)
#
# self.consoleDock.setWidget(consoleDockContainer)
# self.addDockWidget(Qt.BottomDockWidgetArea, self.consoleDock)
# 创建底部停靠控制台
self.consoleDock = QDockWidget("控制台", self)
self.consoleDock.setStyleSheet("""
QDockWidget {
background-color: #19191b;
color: #ffffff;
border: none;
}
QDockWidget::title {
background-color: #19191b;
padding: 8px 10px;
border-bottom: none;
text-align: left;
font-family: 'Microsoft YaHei', 'Inter', sans-serif;
font-size: 14px;
font-weight: 500;
}
QDockWidget::close-button {
background-color: rgba(89, 100, 113, 0.3);
border: 1px solid rgba(184, 211, 241, 0.2);
icon-size: 10px;
border-radius: 2px;
width: 16px;
height: 16px;
right: 6px;
top: 6px;
}
QDockWidget::float-button {
background-color: rgba(89, 100, 113, 0.3);
border: 1px solid rgba(184, 211, 241, 0.2);
icon-size: 10px;
border-radius: 2px;
width: 16px;
height: 16px;
right: 26px;
top: 6px;
}
QDockWidget::close-button:hover, QDockWidget::float-button:hover {
background-color: rgba(89, 100, 113, 0.5);
border: 1px solid rgba(184, 211, 241, 0.3);
}
QDockWidget::close-button:pressed, QDockWidget::float-button:pressed {
background-color: #3067c0;
border: 1px solid rgba(48, 103, 192, 0.6);
}
""")
self.consoleView = CustomConsoleDockWidget(self.world)
# 为控制台添加样式
self.consoleView.setStyleSheet("""
QTextEdit {
background-color: #19191b;
color: #ebebeb;
border: none;
font-family: 'Consolas', 'Monaco', 'Microsoft YaHei', monospace;
font-size: 10px;
font-weight: 300;
}
""")
# 创建包装容器,添加标题下方的分隔线
consoleDockContainer = QWidget()
consoleDockContainer.setStyleSheet("QWidget { background-color: #19191b; }")
consoleDockLayout = QVBoxLayout(consoleDockContainer)
consoleDockLayout.setContentsMargins(0, 0, 0, 0)
consoleDockLayout.setSpacing(0)
# 添加带左右间距的分隔线
consoleSeparator = QFrame()
consoleSeparator.setFrameShape(QFrame.HLine)
consoleSeparator.setFrameShadow(QFrame.Plain)
consoleSeparator.setStyleSheet("""
QFrame {
background-color: rgba(77, 116, 189, 0.4);
max-height: 1px;
margin-left: 8px;
margin-right: 8px;
border: none;
}
""")
consoleDockLayout.addWidget(consoleSeparator)
consoleDockLayout.addWidget(self.consoleView)
self.consoleDock.setWidget(consoleDockContainer)
self.addDockWidget(Qt.BottomDockWidgetArea, self.consoleDock)
# 配置Dock区域的角落归属
# 使右侧和下侧的Dock面板可以占据右下角区域
@ -2414,7 +2650,7 @@ class MainWindow(QMainWindow):
# 确保其他面板也正常显示
self.bottomDock.raise_()
#self.consoleDock.raise_()
self.consoleDock.raise_()
self.leftDock.raise_()
# =========================================================================
# ↓↓↓ 为停靠窗口的标签栏QTabBar设置统一样式根据Figma设计↓↓↓
@ -3929,70 +4165,181 @@ class MainWindow(QMainWindow):
self.world.setCurrentTool(None)
print("工具栏: 取消选择工具")
# def openWebBrowser_win(self):
# """
# 使用 QMainWindow 窗口显示网页
# 创建独立的 Web 浏览器窗口
# """
# from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget
# from PyQt5.QtWebEngineWidgets import QWebEngineView
# from PyQt5.QtCore import QUrl
#
# # 创建独立的浏览器窗口
# window = QMainWindow(self)
# window.setWindowTitle("Web浏览器")
# window.setGeometry(100, 100, 1024, 768)
#
# # 创建中央部件和布局
# central_widget = QWidget()
# window.setCentralWidget(central_widget)
# layout = QVBoxLayout(central_widget)
#
# # 创建 WebEngine 视图
# web_view = QWebEngineView()
# web_view.load(QUrl("https://www.baidu.com"))
#
# # 添加到布局
# layout.addWidget(web_view)
#
# # 显示窗口
# window.show()
def openWebBrowser_win(self):
"""
在独立进程中运行Web浏览器无终端窗口
避免与Panda3D的OpenGL上下文冲突
"""
import subprocess
import sys
import os
# 获取当前脚本目录
current_dir = os.path.dirname(os.path.abspath(__file__))
browser_script = os.path.join(current_dir, '..', 'standalone_web_browser.py')
# 在独立进程中启动Web浏览器不创建终端窗口
"""打开Web浏览器面板使用独立进程避免与Panda3D冲突"""
try:
if sys.platform == "win32":
subprocess.Popen([sys.executable, browser_script],
creationflags=subprocess.CREATE_NO_WINDOW)
else:
subprocess.Popen([sys.executable, browser_script])
print("✓ 独立Web浏览器已在后台启动")
except Exception as e:
print(f"✗ 启动独立Web浏览器失败: {e}")
# 如果启动失败,则使用系统默认浏览器作为备选方案
import webbrowser
webbrowser.open("https://www.baidu.com")
from PyQt5.QtWidgets import QDockWidget, QWidget, QVBoxLayout
from PyQt5.QtCore import QProcess, Qt
import subprocess
import sys
QWebEngineSettings = None
print("⚠ QtWebEngineWidgets 未找到Web 浏览器功能将不可用")
main_window = self.world.main_window
# 尝试获取主窗口引用
if main_window is None:
print("🔍 尝试获取主窗口引用...")
if hasattr(self.world, 'interface_manager'):
print(f" - interface_manager 存在: {self.world.interface_manager}")
if hasattr(self.world.interface_manager, 'main_window'):
main_window = self.world.interface_manager.main_window
print(f" - interface_manager.main_window: {main_window}")
if main_window is None and hasattr(self.world, 'main_window'):
main_window = self.world.main_window
print(f" - world.main_window: {main_window}")
if main_window is None and self.world.treeWidget:
try:
main_window = self.world.treeWidget.window()
print(f" - 从 treeWidget 获取窗口: {main_window}")
except:
pass
if main_window is None:
print("✗ 无法获取主窗口引用")
UniversalMessageDialog.show_warning(
self, "错误", "无法获取主窗口引用", False, "确定"
)
return None
else:
print(f"✅ 使用传入的主窗口引用: {main_window}")
# 检查主窗口是否有效
if not hasattr(main_window, 'addDockWidget'):
print(f"✗ 主窗口引用无效,缺少 addDockWidget 方法")
return None
# 检查是否已经存在浏览器视图
for element in self.world.gui_elements:
if hasattr(element, 'objectName') and element.objectName() == "WebBrowserView":
print("⚠ 浏览器视图已经存在")
element.show()
element.raise_()
return element
print(f"🔧 创建浏览器停靠窗口(独立进程模式),父窗口: {main_window}")
# 创建停靠窗口
browser_dock = QDockWidget("信息面板", main_window)
browser_dock.setObjectName("WebBrowserView")
# 创建容器 Widget
container_widget = QWidget()
container_layout = QVBoxLayout(container_widget)
container_layout.setContentsMargins(0, 0, 0, 0)
# 创建一个占位 Widget用于嵌入外部进程窗口
embed_widget = QWidget()
embed_widget.setMinimumSize(400, 300)
container_layout.addWidget(embed_widget)
browser_dock.setWidget(container_widget)
# 添加到主窗口
print("📍 将浏览器视图添加到主窗口")
main_window.addDockWidget(Qt.RightDockWidgetArea, browser_dock)
# 获取嵌入窗口的 ID
embed_window_id = int(embed_widget.winId())
print(f"🔑 嵌入窗口 ID: {embed_window_id}")
# 启动独立进程
print("🚀 启动独立 WebEngine 进程...")
#web_process_script = os.path.join(os.path.dirname(__file__), "web_browser_process.py")
import tempfile
temp_dir = tempfile.gettempdir()
web_process_script = os.path.join(temp_dir, "web_browser_process_temp.py")
with open(web_process_script, "w", encoding="utf-8") as f:
f.write(WEB_BROWSER_PROCESS_CODE)
# -----------------------------------------------------
# 创建 QProcess注意必须在 start 之前)
# -----------------------------------------------------
# -----------------------------------------------------
# 创建 QProcess注意必须在 start 之前)
# -----------------------------------------------------
process = QProcess(browser_dock)
browser_dock.web_process = process # 保存进程引用
# -----------------------------------------------------
# 输出信号
# -----------------------------------------------------
def on_process_output():
output = bytes(process.readAllStandardOutput()).decode('utf-8', errors='ignore')
if output.strip():
print(f"[WebProcess] {output.strip()}")
def on_process_error():
error = bytes(process.readAllStandardError()).decode('utf-8', errors='ignore')
if error.strip():
print(f"[WebProcess Error] {error.strip()}")
def on_process_finished(exit_code, exit_status):
print(f"⚠️ WebEngine 进程退出: {exit_code} {exit_status}")
process.readyReadStandardOutput.connect(on_process_output)
process.readyReadStandardError.connect(on_process_error)
process.finished.connect(on_process_finished)
# -----------------------------------------------------
# 写入临时脚本
# -----------------------------------------------------
import tempfile
temp_dir = tempfile.gettempdir()
web_process_script = os.path.join(temp_dir, "web_browser_process_temp.py")
with open(web_process_script, "w", encoding="utf-8") as f:
f.write(WEB_BROWSER_PROCESS_CODE)
# -----------------------------------------------------
# 启动子进程(这里顺序不能错)
# -----------------------------------------------------
python_exe = sys.executable
url = "https://baidu.com" # 更可控的测试站点
print(f"🚀 启动: {python_exe} {web_process_script} {url} {embed_window_id}")
process.start(python_exe, [web_process_script, url, str(embed_window_id)])
if not process.waitForStarted(3000):
print("✗ 启动 WebEngine 失败")
return None
print("✓ WebEngine 进程已启动")
# 添加到GUI元素列表以便管理
self.world.gui_elements.append(browser_dock)
# 添加清理函数
def cleanup_process():
if hasattr(browser_dock, 'web_process') and browser_dock.web_process:
print("🧹 清理 WebEngine 进程...")
browser_dock.web_process.terminate()
if not browser_dock.web_process.waitForFinished(2000):
browser_dock.web_process.kill()
browser_dock.destroyed.connect(cleanup_process)
print("✓ 网页浏览器视图已创建并集成到项目中(独立进程模式)")
return browser_dock
except Exception as e:
print(f"✗ 创建浏览器视图失败: {str(e)}")
import traceback
traceback.print_exc()
UniversalMessageDialog.show_error(
self, "错误",
f"创建浏览器视图失败:\n{str(e)}",
False, "确定"
)
return None
def openWebBrowser(self):
if not WEB_ENGINE_AVAILABLE:
return None
try:
#from PyQt5.QtWebEngineWidgets import QWebEngineView
# from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QDockWidget
from PyQt5.QtCore import QUrl
import os
@ -6348,7 +6695,17 @@ def setup_main_window(world,path = None):
QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
if sys.platform == 'win32':
QCoreApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
# 添加 Chromium 参数禁用硬件加速,避免与 Panda3D 的 OpenGL 冲突
sys.argv.extend([
'--disable-gpu',
'--disable-software-rasterizer',
'--disable-gpu-compositing',
'--disable-accelerated-2d-canvas',
'--num-raster-threads=1'
])
app = QApplication(sys.argv)
print("✓ QApplication 已创建QtWebEngine 硬件加速已禁用")
main_window = MainWindow(world)
main_window.show()