Commit da148b05 by yhb

123456

parent 7cf1afc7
...@@ -29,10 +29,11 @@ print("[环境变量] OpenMP冲突已修复") ...@@ -29,10 +29,11 @@ print("[环境变量] OpenMP冲突已修复")
from qtpy import QtWidgets from qtpy import QtWidgets
from app import MainWindow # 延迟导入,避免在 QApplication 创建前创建 QWidget
# from app import MainWindow
from database.config import get_config, get_temp_models_dir from database.config import get_config, get_temp_models_dir
from widgets.style_manager import FontManager # from widgets.style_manager import FontManager
from widgets.responsive_layout import ResponsiveLayout # from widgets.responsive_layout import ResponsiveLayout
def setup_logging(level: str = "info"): def setup_logging(level: str = "info"):
...@@ -270,6 +271,11 @@ def _main(): ...@@ -270,6 +271,11 @@ def _main():
app.setApplicationName('Detection') app.setApplicationName('Detection')
app.setOrganizationName('Detection') app.setOrganizationName('Detection')
# 在 QApplication 创建后导入可能创建 QWidget 的模块
from app import MainWindow
from widgets.style_manager import FontManager
from widgets.responsive_layout import ResponsiveLayout
# 初始化响应式布局系统 # 初始化响应式布局系统
ResponsiveLayout.initialize(app) ResponsiveLayout.initialize(app)
......
...@@ -686,6 +686,10 @@ class MainWindow( ...@@ -686,6 +686,10 @@ class MainWindow(
from widgets import ChannelPanel, MissionPanel, CurvePanel from widgets import ChannelPanel, MissionPanel, CurvePanel
# 主页面容器 # 主页面容器
# 修复:确保 QApplication 完全初始化后再创建 QWidget
app = QtWidgets.QApplication.instance()
if app is None:
raise RuntimeError("QApplication 未初始化")
page = QtWidgets.QWidget() page = QtWidgets.QWidget()
page_layout = QtWidgets.QVBoxLayout(page) page_layout = QtWidgets.QVBoxLayout(page)
page_layout.setContentsMargins(0, 0, 0, 0) page_layout.setContentsMargins(0, 0, 0, 0)
...@@ -714,6 +718,10 @@ class MainWindow( ...@@ -714,6 +718,10 @@ class MainWindow(
except ImportError: except ImportError:
from widgets import ChannelPanel, MissionPanel from widgets import ChannelPanel, MissionPanel
# 确保 QApplication 存在
app = QtWidgets.QApplication.instance()
if app is None:
raise RuntimeError("QApplication 未初始化")
layout_widget = QtWidgets.QWidget() layout_widget = QtWidgets.QWidget()
main_layout = QtWidgets.QHBoxLayout(layout_widget) main_layout = QtWidgets.QHBoxLayout(layout_widget)
main_layout.setContentsMargins(10, 10, 10, 10) main_layout.setContentsMargins(10, 10, 10, 10)
......
...@@ -69,6 +69,7 @@ class TrainingWorker(QThread): ...@@ -69,6 +69,7 @@ class TrainingWorker(QThread):
super().__init__() super().__init__()
self.training_params = training_params self.training_params = training_params
self.is_running = True self.is_running = True
self.training_actually_started = False # 标记训练是否已经真正开始(第一个epoch开始)
self.train_config = None self.train_config = None
# 调试信息:显示传入的训练参数 # 调试信息:显示传入的训练参数
...@@ -522,6 +523,8 @@ class TrainingWorker(QThread): ...@@ -522,6 +523,8 @@ class TrainingWorker(QThread):
def on_train_start(trainer): def on_train_start(trainer):
"""训练开始回调 - 只输出到终端,不发送到UI""" """训练开始回调 - 只输出到终端,不发送到UI"""
# 标记训练已经真正开始
self.training_actually_started = True
# 记录开始时间 # 记录开始时间
epoch_start_time[0] = time.time() epoch_start_time[0] = time.time()
# 不发送任何格式化消息到UI,让LogCapture直接捕获原生输出 # 不发送任何格式化消息到UI,让LogCapture直接捕获原生输出
...@@ -1264,3 +1267,7 @@ class TrainingWorker(QThread): ...@@ -1264,3 +1267,7 @@ class TrainingWorker(QThread):
def stop_training(self): def stop_training(self):
"""停止训练""" """停止训练"""
self.is_running = False self.is_running = False
def has_training_started(self):
"""检查训练是否已经真正开始"""
return self.training_actually_started
...@@ -1900,6 +1900,10 @@ class ChannelPanelHandler: ...@@ -1900,6 +1900,10 @@ class ChannelPanelHandler:
def _initConfigFileWatcher(self): def _initConfigFileWatcher(self):
"""初始化配置文件监控器""" """初始化配置文件监控器"""
try: try:
# 临时禁用配置文件监控器以解决 QWidget 创建顺序问题
print(f"[ConfigWatcher] 配置文件监控器已禁用(避免 QWidget 创建顺序问题)")
return
# 获取配置文件路径 # 获取配置文件路径
project_root = get_project_root() project_root = get_project_root()
config_path = os.path.join(project_root, 'database', 'config', 'default_config.yaml') config_path = os.path.join(project_root, 'database', 'config', 'default_config.yaml')
...@@ -1928,7 +1932,12 @@ class ChannelPanelHandler: ...@@ -1928,7 +1932,12 @@ class ChannelPanelHandler:
print(f"🔄 [ConfigWatcher] 检测到配置文件变化: {path}") print(f"🔄 [ConfigWatcher] 检测到配置文件变化: {path}")
# 延迟一小段时间,确保文件写入完成 # 延迟一小段时间,确保文件写入完成
# 修复:检查 QApplication 是否存在
if QtWidgets.QApplication.instance() is not None:
QtCore.QTimer.singleShot(100, self._reloadChannelConfig) QtCore.QTimer.singleShot(100, self._reloadChannelConfig)
else:
# 如果没有 QApplication,直接调用重载函数
self._reloadChannelConfig()
except Exception as e: except Exception as e:
print(f"[ConfigWatcher] 处理配置文件变化失败: {e}") print(f"[ConfigWatcher] 处理配置文件变化失败: {e}")
......
...@@ -17,7 +17,7 @@ import csv ...@@ -17,7 +17,7 @@ import csv
import datetime import datetime
import numpy as np import numpy as np
from qtpy import QtWidgets, QtCore from qtpy import QtWidgets, QtCore
from PyQt5.QtCore import QThread, pyqtSignal from qtpy.QtCore import QThread, Signal as pyqtSignal
# 导入图标工具 # 导入图标工具
try: try:
...@@ -930,7 +930,7 @@ class CurvePanelHandler: ...@@ -930,7 +930,7 @@ class CurvePanelHandler:
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
# 🔥 延迟关闭进度条,确保用户能看到(至少显示500ms) # 🔥 延迟关闭进度条,确保用户能看到(至少显示500ms)
from PyQt5.QtCore import QTimer from qtpy.QtCore import QTimer
QTimer.singleShot(500, progress_dialog.close) QTimer.singleShot(500, progress_dialog.close)
print(f"✅ [进度条] 将在500ms后关闭") print(f"✅ [进度条] 将在500ms后关闭")
......
...@@ -11,7 +11,7 @@ widgets/videopage/historypanel.py (HistoryPanel) ...@@ -11,7 +11,7 @@ widgets/videopage/historypanel.py (HistoryPanel)
- -
""" """
from PyQt5 import QtWidgets, QtCore from qtpy import QtWidgets, QtCore
class HistoryPanelHandler: class HistoryPanelHandler:
...@@ -80,8 +80,8 @@ class HistoryPanelHandler: ...@@ -80,8 +80,8 @@ class HistoryPanelHandler:
return return
import os import os
from PyQt5.QtMultimedia import QMediaPlayer from qtpy.QtMultimedia import QMediaPlayer
from PyQt5 import QtWidgets from qtpy import QtWidgets
player = self.history_panel._media_player player = self.history_panel._media_player
print(f"[HistoryPanelHandler] 播放器: {player}") print(f"[HistoryPanelHandler] 播放器: {player}")
...@@ -158,7 +158,7 @@ class HistoryPanelHandler: ...@@ -158,7 +158,7 @@ class HistoryPanelHandler:
if not self.history_panel or not hasattr(self.history_panel, 'play_pause_button'): if not self.history_panel or not hasattr(self.history_panel, 'play_pause_button'):
return return
from PyQt5.QtMultimedia import QMediaPlayer from qtpy.QtMultimedia import QMediaPlayer
from widgets.style_manager import newIcon from widgets.style_manager import newIcon
button = self.history_panel.play_pause_button button = self.history_panel.play_pause_button
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
根据屏幕分辨率自动调整UI尺寸 根据屏幕分辨率自动调整UI尺寸
""" """
from PyQt5 import QtWidgets, QtCore from qtpy import QtWidgets, QtCore
class ResponsiveLayout: class ResponsiveLayout:
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
统一样式管理器 统一样式管理器
...@@ -40,7 +40,7 @@ import os.path as osp ...@@ -40,7 +40,7 @@ import os.path as osp
import sys import sys
try: try:
from PyQt5 import QtGui, QtWidgets, QtCore from qtpy import QtGui, QtWidgets, QtCore
except ImportError as e: except ImportError as e:
raise raise
...@@ -78,12 +78,11 @@ class FontManager: ...@@ -78,12 +78,11 @@ class FontManager:
@staticmethod @staticmethod
def getDefaultFont(): def getDefaultFont():
"""获取默认字体""" """获取默认字体"""
font = QtGui.QFont( return FontManager.getFont(
FontManager.DEFAULT_FONT_FAMILY, size=FontManager.DEFAULT_FONT_SIZE,
FontManager.DEFAULT_FONT_SIZE weight=FontManager.DEFAULT_FONT_WEIGHT,
family=FontManager.DEFAULT_FONT_FAMILY
) )
font.setWeight(FontManager.DEFAULT_FONT_WEIGHT)
return font
@staticmethod @staticmethod
def getFont(size=None, weight=None, italic=False, underline=False, family=None): def getFont(size=None, weight=None, italic=False, underline=False, family=None):
...@@ -96,7 +95,31 @@ class FontManager: ...@@ -96,7 +95,31 @@ class FontManager:
weight = FontManager.DEFAULT_FONT_WEIGHT weight = FontManager.DEFAULT_FONT_WEIGHT
font = QtGui.QFont(family, size) font = QtGui.QFont(family, size)
# PySide6兼容性:将整数权重转换为QFont.Weight枚举
try:
# 尝试使用PySide6的Weight枚举
if hasattr(QtGui.QFont, 'Weight'):
if weight <= 25:
font.setWeight(QtGui.QFont.Weight.Light)
elif weight <= 50:
font.setWeight(QtGui.QFont.Weight.Normal)
elif weight <= 63:
font.setWeight(QtGui.QFont.Weight.DemiBold)
elif weight <= 75:
font.setWeight(QtGui.QFont.Weight.Bold)
else:
font.setWeight(QtGui.QFont.Weight.Black)
else:
# 回退到旧的整数方式(PyQt5)
font.setWeight(weight) font.setWeight(weight)
except (AttributeError, TypeError):
# 如果出现任何错误,使用默认权重
try:
font.setWeight(QtGui.QFont.Weight.Normal)
except:
pass
font.setItalic(italic) font.setItalic(italic)
font.setUnderline(underline) font.setUnderline(underline)
return font return font
...@@ -157,8 +180,17 @@ class FontManager: ...@@ -157,8 +180,17 @@ class FontManager:
@staticmethod @staticmethod
def applyToApplication(app): def applyToApplication(app):
"""应用默认字体到整个应用程序""" """应用默认字体到整个应用程序"""
font = FontManager.getDefaultFont() try:
# 确保使用当前 Qt 后端创建字体对象
from qtpy import QtGui
font = QtGui.QFont(
FontManager.DEFAULT_FONT_FAMILY,
FontManager.DEFAULT_FONT_SIZE
)
font.setWeight(FontManager.DEFAULT_FONT_WEIGHT)
app.setFont(font) app.setFont(font)
except Exception as e:
print(f"字体设置失败,使用默认字体: {e}")
@staticmethod @staticmethod
def applyToWidgetRecursive(widget, size=None, weight=None): def applyToWidgetRecursive(widget, size=None, weight=None):
...@@ -827,7 +859,7 @@ class TextButtonStyleManager: ...@@ -827,7 +859,7 @@ class TextButtonStyleManager:
# 计算文本宽度:字符数 * 每字符宽度 + 内边距 # 计算文本宽度:字符数 * 每字符宽度 + 内边距
text_width = len(text) * cls.CHAR_WIDTH + cls.MIN_PADDING text_width = len(text) * cls.CHAR_WIDTH + cls.MIN_PADDING
# 返回基础宽度和计算宽度的较大值
return max(cls.BASE_WIDTH, text_width) return max(cls.BASE_WIDTH, text_width)
@classmethod @classmethod
...@@ -850,7 +882,14 @@ class TextButtonStyleManager: ...@@ -850,7 +882,14 @@ class TextButtonStyleManager:
@classmethod @classmethod
def createStandardButton(cls, text, parent=None, slot=None): def createStandardButton(cls, text, parent=None, slot=None):
"""创建标准样式的文本按钮""" """创建标准样式的文本按钮"""
button = QtWidgets.QPushButton(text, parent) # 修复 PySide6 兼容性问题 - 分步创建
try:
button = QtWidgets.QPushButton(text)
if parent is not None:
button.setParent(parent)
except Exception as e:
print(f"按钮创建失败: {e}")
button = QtWidgets.QPushButton("按钮")
# 应用标准样式 # 应用标准样式
cls.applyToButton(button, text) cls.applyToButton(button, text)
...@@ -867,6 +906,37 @@ class TextButtonStyleManager: ...@@ -867,6 +906,37 @@ class TextButtonStyleManager:
button.setText(new_text) button.setText(new_text)
cls.applyToButton(button, new_text) cls.applyToButton(button, new_text)
@classmethod
def applyDangerStyle(cls, button):
"""应用危险按钮样式(红色)"""
button.setStyleSheet("""
QPushButton {
background-color: #dc3545;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-weight: bold;
min-width: 100px;
}
QPushButton:hover {
background-color: #c82333;
}
QPushButton:pressed {
background-color: #bd2130;
}
QPushButton:disabled {
background-color: #6c757d;
color: #ffffff;
}
""")
@classmethod
def applyStandardStyle(cls, button):
"""应用标准按钮样式"""
# 重新应用标准样式
cls.applyToButton(button)
class BackgroundStyleManager: class BackgroundStyleManager:
"""全局背景颜色管理器""" """全局背景颜色管理器"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment