diff --git a/ui/main_window.py b/ui/main_window.py index fe94df64..7964bdd9 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -1,4 +1,5 @@ -""" + +""" 主窗口设置模块 负责主窗口的界面构建和事件绑定: @@ -10,7 +11,18 @@ import os import sys from PyQt5.QtGui import QKeySequence, QIcon, QPalette, QColor -# from PyQt5.QtWebEngineWidgets import QWebEngineView + +# QtWebEngine 导入(环境变量已在 main.py 中配置) +try: + from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings + WEB_ENGINE_AVAILABLE = True + print("✓ QtWebEngineWidgets 已导入") +except ImportError: + WEB_ENGINE_AVAILABLE = False + QWebEngineView = None + + + from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction, QDockWidget, QTreeWidget, QListWidget, QWidget, QVBoxLayout, QTreeWidgetItem, QLabel, QLineEdit, QFormLayout, QDoubleSpinBox, QScrollArea, @@ -1504,7 +1516,12 @@ 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) + + if sys.platform == 'win32': + self.webBrowserAction.triggered.connect(self.openWebBrowser_win) + else: + self.webBrowserAction.triggered.connect(self.openWebBrowser) + def getCreateMenuActions(self): """获取所有创建菜单动作的字典 - 供右键菜单使用""" @@ -2290,90 +2307,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面板可以占据右下角区域 @@ -2397,7 +2414,7 @@ class MainWindow(QMainWindow): # 确保其他面板也正常显示 self.bottomDock.raise_() - self.consoleDock.raise_() + #self.consoleDock.raise_() self.leftDock.raise_() # ========================================================================= # ↓↓↓ 为停靠窗口的标签栏(QTabBar)设置统一样式(根据Figma设计)↓↓↓ @@ -3912,11 +3929,70 @@ 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浏览器,不创建终端窗口 + 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") + + QWebEngineSettings = None + print("⚠ QtWebEngineWidgets 未找到,Web 浏览器功能将不可用") + 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 @@ -3975,8 +4051,8 @@ class MainWindow(QMainWindow): self.web_view = QWebEngineView() # 加载百度网页 - #print("🌐 加载百度网页: https://www.baidu.com") - #self.web_view.load(QUrl("https://www.bootstrapmb.com/item/15762/preview")) + # print("🌐 加载百度网页: https://www.baidu.com") + # self.web_view.load(QUrl("https://www.bootstrapmb.com/item/15762/preview")) self.web_view.load(QUrl("https://www.baidu.com")) # 设置内容 @@ -3999,7 +4075,6 @@ class MainWindow(QMainWindow): return None - def getSampleWeatherData(self): """获取示例天气数据""" try: