feat(core): 优化主窗口和管理器功能

- 在主窗口中重构初始化逻辑,增强UI组件的管理和信号连接,提升代码可读性。
- 添加资源验证和加载测试功能,确保关键资源文件的完整性和可用性。
- 更新下载管理器和离线模式管理器,优化线程管理和状态更新,提升用户体验。
- 增强日志记录,确保在关键操作中提供详细的调试信息,便于后续排查和用户反馈。
- 删除不再使用的进度窗口创建函数,改为由UIManager管理,提升代码整洁性。
This commit is contained in:
hyb-oyqq
2025-08-11 17:42:52 +08:00
parent dc433a2ac9
commit 68bbafc564
12 changed files with 842 additions and 551 deletions

View File

@@ -4,13 +4,14 @@ import subprocess
import shutil
import json
import webbrowser
import traceback
from PySide6 import QtWidgets
from PySide6.QtCore import QTimer, Qt, QPoint, QRect, QSize
from PySide6.QtWidgets import QMainWindow, QMessageBox, QGraphicsOpacityEffect, QGraphicsColorizeEffect, QDialog, QVBoxLayout, QProgressBar, QLabel
from PySide6.QtGui import QPalette, QColor, QPainterPath, QRegion, QFont
from PySide6.QtGui import QAction # Added for menu actions
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QProgressBar, QLabel # Added for progress window
# Removed QDialog, QVBoxLayout, QProgressBar, QLabel from here as they are managed by UIManager
from ui.Ui_install import Ui_MainWindows
from config.config import (
@@ -22,8 +23,8 @@ from utils import (
load_config, save_config, HashManager, AdminPrivileges, msgbox_frame, load_image_from_file
)
from workers import (
DownloadThread, ProgressWindow, IpOptimizerThread,
HashThread, ExtractionThread, ConfigFetchThread
IpOptimizerThread,
HashThread, ExtractionThread, ConfigFetchThread, DownloadThread
)
from core import (
MultiStageAnimations, UIManager, DownloadManager, DebugManager,
@@ -41,166 +42,251 @@ class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 设置窗口为无边框
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
# 设置窗口背景透明
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self._setup_window_properties()
self._init_ui()
self._init_config_and_tools()
self._init_managers()
self._connect_signals()
self._setup_environment()
# 调整窗口大小以适应背景图片比例 (1280x720)
self.download_manager.hosts_manager.backup()
self._setup_debug_mode()
self.check_and_set_offline_mode()
self.fetch_cloud_config()
self.start_animations()
def _setup_window_properties(self):
"""设置窗口的基本属性,如无边框、透明背景和大小."""
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self.resize(1280, 720)
# 设置固定尺寸范围
self.setMinimumSize(QSize(1024, 576))
self.setMaximumSize(QSize(1280, 720))
# 初始化UI (从Ui_install.py导入)
def _init_ui(self):
"""初始化UI组件."""
self.ui = Ui_MainWindows()
self.ui.setupUi(self)
# 初始化配置
def _init_config_and_tools(self):
"""加载配置并初始化核心工具."""
self.config = load_config()
# 初始化工具类
self.hash_manager = HashManager(BLOCK_SIZE)
self.admin_privileges = AdminPrivileges()
# 初始化哈希校验窗口引用
self.hash_msg_box = None
self.loading_dialog = None
self.patch_detector = PatchDetector(self)
# 初始化各种管理器 - 调整初始化顺序,避免循环依赖
# 1. 首先创建必要的基础管理器
self.animator = MultiStageAnimations(self.ui, self)
self.window_manager = WindowManager(self)
self.debug_manager = DebugManager(self)
# 2. 初始化IPv6Manager(应在UIManager之前)
self.ipv6_manager = IPv6Manager(self)
# 3. 创建UIManager(依赖IPv6Manager)
self.ui_manager = UIManager(self)
# 4. 为debug_manager设置ui_manager引用
self.debug_manager.set_ui_manager(self.ui_manager)
# 5. 初始化其他管理器
self.config_manager = ConfigManager(APP_NAME, CONFIG_URL, UA, self.debug_manager)
self.game_detector = GameDetector(GAME_INFO, self.debug_manager)
self.patch_manager = PatchManager(APP_NAME, GAME_INFO, self.debug_manager, self)
# 6. 初始化补丁检测模块
self.patch_detector = PatchDetector(self)
# 7. 设置补丁检测器到补丁管理器
self.patch_manager.set_patch_detector(self.patch_detector)
# 8. 初始化离线模式管理器
from core.offline_mode_manager import OfflineModeManager
self.offline_mode_manager = OfflineModeManager(self)
# 9. 初始化下载管理器 - 放在最后,因为它可能依赖于其他管理器
self.download_manager = DownloadManager(self)
# 10. 初始化功能处理程序
self.uninstall_handler = UninstallHandler(self)
self.patch_toggle_handler = PatchToggleHandler(self)
# 加载用户下载线程设置
if "download_thread_level" in self.config and self.config["download_thread_level"] in DOWNLOAD_THREADS:
self.download_manager.download_thread_level = self.config["download_thread_level"]
# 初始化状态变量
self.cloud_config = None
self.config_valid = False # 添加配置有效标志
self.patch_manager.initialize_status()
self.installed_status = self.patch_manager.get_status() # 获取初始化后的状态
self.last_error_message = "" # 添加错误信息记录
self.version_warning = False # 添加版本警告标志
self.install_button_enabled = True # 默认启用安装按钮
self.config_valid = False
self.last_error_message = ""
self.version_warning = False
self.install_button_enabled = True
self.progress_window = None
# 线程持有引用,避免 QThread 在运行中被销毁
self.pre_hash_thread = None
self.hash_thread = None # after 校验线程引用(由 PatchDetector 赋值)
self.hash_thread = None
# 设置关闭按钮事件连接
# 验证关键资源
self._verify_resources()
def _verify_resources(self):
"""验证关键资源文件是否存在,帮助调试资源加载问题"""
from utils import resource_path
logger.info("开始验证关键资源文件...")
# 关键字体文件
font_files = [
os.path.join("assets", "fonts", "SmileySans-Oblique.ttf")
]
# 关键图标文件
icon_files = [
os.path.join("assets", "images", "ICO", "icon.png"),
os.path.join("assets", "images", "ICO", "icon.ico"),
os.path.join("assets", "images", "BTN", "Button.png"),
os.path.join("assets", "images", "BTN", "exit.bmp"),
os.path.join("assets", "images", "BTN", "start_install.bmp")
]
# 关键背景图片
bg_files = [
os.path.join("assets", "images", "BG", "bg1.jpg"),
os.path.join("assets", "images", "BG", "bg2.jpg"),
os.path.join("assets", "images", "BG", "bg3.jpg"),
os.path.join("assets", "images", "BG", "bg4.jpg"),
os.path.join("assets", "images", "BG", "menubg.jpg")
]
# 记录缺失的资源
missing_resources = []
# 验证字体文件
for font_file in font_files:
path = resource_path(font_file)
if not os.path.exists(path):
missing_resources.append(font_file)
logger.warning(f"缺失字体文件: {font_file}, 尝试路径: {path}")
else:
logger.info(f"已找到字体文件: {font_file}")
# 验证图标文件
for icon_file in icon_files:
path = resource_path(icon_file)
if not os.path.exists(path):
missing_resources.append(icon_file)
logger.warning(f"缺失图标文件: {icon_file}, 尝试路径: {path}")
else:
logger.info(f"已找到图标文件: {icon_file}")
# 验证背景图片
for bg_file in bg_files:
path = resource_path(bg_file)
if not os.path.exists(path):
missing_resources.append(bg_file)
logger.warning(f"缺失背景图片: {bg_file}, 尝试路径: {path}")
else:
logger.info(f"已找到背景图片: {bg_file}")
# 如果有缺失资源,记录摘要
if missing_resources:
logger.error(f"总计 {len(missing_resources)} 个关键资源文件缺失!")
# 如果在调试模式下,显示警告对话框
if self.config.get("debug_mode", False):
from PySide6.QtWidgets import QMessageBox
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setWindowTitle("资源加载警告")
msg.setText("检测到缺失的关键资源文件!")
msg.setInformativeText(f"{len(missing_resources)} 个资源文件未找到。\n请检查日志文件获取详细信息。")
msg.setStandardButtons(QMessageBox.Ok)
msg.exec()
else:
logger.info("所有关键资源文件验证通过")
# 测试资源加载功能
self._test_resource_loading()
def _test_resource_loading(self):
"""测试资源加载功能,验证图片和字体是否可以正确加载"""
logger.info("开始测试资源加载功能...")
from PySide6.QtGui import QFontDatabase, QPixmap, QImage, QFont
from utils import resource_path, load_image_from_file
# 测试字体加载
logger.info("测试字体加载...")
font_path = resource_path(os.path.join("assets", "fonts", "SmileySans-Oblique.ttf"))
if os.path.exists(font_path):
font_id = QFontDatabase.addApplicationFont(font_path)
if font_id != -1:
font_families = QFontDatabase.applicationFontFamilies(font_id)
if font_families:
logger.info(f"字体加载测试成功: {font_families[0]}")
else:
logger.error("字体加载测试失败: 无法获取字体族")
else:
logger.error(f"字体加载测试失败: 无法加载字体文件 {font_path}")
else:
logger.error(f"字体加载测试失败: 文件不存在 {font_path}")
# 测试图片加载 - 使用QPixmap直接加载
logger.info("测试图片加载 (QPixmap)...")
icon_path = resource_path(os.path.join("assets", "images", "ICO", "icon.png"))
if os.path.exists(icon_path):
pixmap = QPixmap(icon_path)
if not pixmap.isNull():
logger.info(f"QPixmap加载测试成功: {icon_path}, 大小: {pixmap.width()}x{pixmap.height()}")
else:
logger.error(f"QPixmap加载测试失败: {icon_path}")
else:
logger.error(f"QPixmap加载测试失败: 文件不存在 {icon_path}")
# 测试图片加载 - 使用QImage加载
logger.info("测试图片加载 (QImage)...")
bg_path = resource_path(os.path.join("assets", "images", "BG", "bg1.jpg"))
if os.path.exists(bg_path):
image = QImage(bg_path)
if not image.isNull():
logger.info(f"QImage加载测试成功: {bg_path}, 大小: {image.width()}x{image.height()}")
else:
logger.error(f"QImage加载测试失败: {bg_path}")
else:
logger.error(f"QImage加载测试失败: 文件不存在 {bg_path}")
# 测试自定义加载函数
logger.info("测试自定义图片加载函数...")
btn_path = resource_path(os.path.join("assets", "images", "BTN", "Button.png"))
pixmap = load_image_from_file(btn_path)
if not pixmap.isNull():
logger.info(f"自定义图片加载函数测试成功: {btn_path}, 大小: {pixmap.width()}x{pixmap.height()}")
else:
logger.error(f"自定义图片加载函数测试失败: {btn_path}")
logger.info("资源加载功能测试完成")
def _init_managers(self):
"""初始化所有管理器."""
self.animator = MultiStageAnimations(self.ui, self)
self.window_manager = WindowManager(self)
self.debug_manager = DebugManager(self)
self.ipv6_manager = IPv6Manager(self)
self.ui_manager = UIManager(self)
self.debug_manager.set_ui_manager(self.ui_manager)
self.config_manager = ConfigManager(APP_NAME, CONFIG_URL, UA, self.debug_manager)
self.game_detector = GameDetector(GAME_INFO, self.debug_manager)
self.patch_manager = PatchManager(APP_NAME, GAME_INFO, self.debug_manager, self)
self.patch_manager.set_patch_detector(self.patch_detector)
from core.managers.offline_mode_manager import OfflineModeManager
self.offline_mode_manager = OfflineModeManager(self)
self.download_manager = DownloadManager(self)
self.uninstall_handler = UninstallHandler(self)
self.patch_toggle_handler = PatchToggleHandler(self)
# Load user's download thread setting
if "download_thread_level" in self.config and self.config["download_thread_level"] in DOWNLOAD_THREADS:
self.download_manager.download_thread_level = self.config["download_thread_level"]
def _connect_signals(self):
"""连接UI组件的信号到相应的槽函数."""
if hasattr(self.ui, 'close_btn'):
self.ui.close_btn.clicked.connect(self.close)
if hasattr(self.ui, 'minimize_btn'):
self.ui.minimize_btn.clicked.connect(self.showMinimized)
# 创建缓存目录
self.ui.start_install_btn.clicked.connect(self.handle_install_button_click)
self.ui.uninstall_btn.clicked.connect(self.uninstall_handler.handle_uninstall_button_click)
self.ui.toggle_patch_btn.clicked.connect(self.patch_toggle_handler.handle_toggle_patch_button_click)
self.ui.exit_btn.clicked.connect(self.shutdown_app)
def _setup_environment(self):
"""准备应用运行所需的环境,如创建缓存目录和检查权限."""
if not os.path.exists(PLUGIN):
try:
os.makedirs(PLUGIN)
except OSError as e:
QtWidgets.QMessageBox.critical(
self,
f"错误 - {APP_NAME}",
f"\n无法创建缓存位置\n\n使用管理员身份运行或检查文件读写权限\n\n【错误信息】:{e}\n",
)
QtWidgets.QMessageBox.critical(self, f"错误 - {APP_NAME}", f"无法创建缓存位置: {e}")
sys.exit(1)
# 连接信号 - 绑定到新按钮
self.ui.start_install_btn.clicked.connect(self.handle_install_button_click)
self.ui.uninstall_btn.clicked.connect(self.uninstall_handler.handle_uninstall_button_click) # 使用卸载处理程序
self.ui.toggle_patch_btn.clicked.connect(self.patch_toggle_handler.handle_toggle_patch_button_click) # 使用补丁切换处理程序
self.ui.exit_btn.clicked.connect(self.shutdown_app)
# 初始化按钮状态标记
self.install_button_enabled = False
self.last_error_message = ""
# 检查管理员权限和进程
try:
# 检查管理员权限
self.admin_privileges.request_admin_privileges()
# 检查并终止相关进程
self.admin_privileges.check_and_terminate_processes()
except KeyboardInterrupt:
logger.warning("权限检查或进程检查被用户中断")
QtWidgets.QMessageBox.warning(
self,
f"警告 - {APP_NAME}",
"\n操作被中断,请重新启动应用。\n"
)
sys.exit(1)
except Exception as e:
logger.error(f"权限检查或进程检查时发生错误: {e}")
QtWidgets.QMessageBox.critical(
self,
f"错误 - {APP_NAME}",
f"\n权限检查或进程检查时发生错误,请重新启动应用。\n\n【错误信息】:{e}\n"
)
logger.error(f"权限或进程检查失败: {e}")
QtWidgets.QMessageBox.critical(self, f"错误 - {APP_NAME}", f"权限检查失败: {e}")
sys.exit(1)
# 备份hosts文件
self.download_manager.hosts_manager.backup()
# 根据初始配置决定是否开启Debug模式
if "debug_mode" in self.config and self.config["debug_mode"]:
# 先启用日志系统
def _setup_debug_mode(self):
"""根据配置设置调试模式."""
if self.config.get("debug_mode"):
self.debug_manager.start_logging()
logger.info("通过配置启动调试模式")
# 检查UI设置
if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action:
if self.ui_manager.debug_action.isChecked():
# 如果通过UI启用了调试模式确保日志系统已启动
if not self.debug_manager.logger:
self.debug_manager.start_logging()
logger.info("通过UI启动调试模式")
# 设置UI包括窗口图标和菜单
if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action and self.ui_manager.debug_action.isChecked():
if not self.debug_manager.logger:
self.debug_manager.start_logging()
logger.info("通过UI启动调试模式")
self.ui_manager.setup_ui()
# 检查是否有离线补丁文件,如果有则自动切换到离线模式
self.check_and_set_offline_mode()
# 获取云端配置
self.fetch_cloud_config()
# 启动动画
self.start_animations()
# 窗口事件处理 - 委托给WindowManager
def mousePressEvent(self, event):
@@ -334,110 +420,19 @@ class MainWindow(QMainWindow):
"""保存配置的便捷方法"""
self.config_manager.save_config(config)
def create_download_thread(self, url, _7z_path, game_version):
"""创建下载线程
Args:
url: 下载URL
_7z_path: 7z文件保存路径
game_version: 游戏版本
Returns:
DownloadThread: 下载线程实例
"""
return DownloadThread(url, _7z_path, game_version, self)
def create_progress_window(self):
"""创建进度窗口
Returns:
QDialog: 进度窗口实例
"""
progress_window = QDialog(self)
progress_window.setWindowTitle(f"下载进度 - {APP_NAME}")
progress_window.setFixedSize(400, 150)
layout = QVBoxLayout()
# 添加进度条
progress_bar = QProgressBar()
progress_bar.setRange(0, 100)
progress_bar.setValue(0)
layout.addWidget(progress_bar)
# 添加标签
status_label = QLabel("准备下载...")
layout.addWidget(status_label)
progress_window.setLayout(layout)
progress_window.progress_bar = progress_bar
progress_window.status_label = status_label
return progress_window
def create_extraction_progress_window(self):
"""创建解压进度窗口
Returns:
QDialog: 解压进度窗口实例
"""
progress_window = QDialog(self)
progress_window.setWindowTitle(f"解压进度 - {APP_NAME}")
progress_window.setFixedSize(400, 150)
layout = QVBoxLayout()
# 添加进度条
progress_bar = QProgressBar()
progress_bar.setRange(0, 100)
progress_bar.setValue(0)
layout.addWidget(progress_bar)
# 添加标签
status_label = QLabel("准备解压...")
layout.addWidget(status_label)
progress_window.setLayout(layout)
progress_window.progress_bar = progress_bar
progress_window.status_label = status_label
return progress_window
def create_extraction_thread(self, _7z_path, game_folder, plugin_path, game_version, extracted_path=None):
"""创建解压线程
Args:
_7z_path: 7z文件路径
game_folder: 游戏文件夹路径
plugin_path: 插件路径
game_version: 游戏版本
extracted_path: 已解压的补丁文件路径,如果提供则直接使用它而不进行解压
Returns:
ExtractionThread: 解压线程实例
"""
return ExtractionThread(_7z_path, game_folder, plugin_path, game_version, self, extracted_path)
def create_hash_thread(self, mode, install_paths, plugin_hash=None, installed_status=None):
"""创建哈希校验线程
Args:
mode: 校验模式,"pre""after"
install_paths: 安装路径字典
plugin_hash: 插件哈希值字典如果为None则使用self.plugin_hash
installed_status: 安装状态字典如果为None则使用self.installed_status
Returns:
HashThread: 哈希校验线程实例
"""
if plugin_hash is None:
plugin_hash = PLUGIN_HASH
if installed_status is None:
installed_status = self.installed_status
return HashThread(mode, install_paths, plugin_hash, installed_status, self)
# Remove create_progress_window, create_extraction_progress_window, show_loading_dialog, hide_loading_dialog
# These are now handled by UIManager
# def create_progress_window(self): ...
# def create_extraction_progress_window(self): ...
# def show_loading_dialog(self, message): ...
# def hide_loading_dialog(self): ...
# Remove create_download_thread, create_extraction_thread, create_hash_thread
# These are now handled by their respective managers or a new ThreadManager if we create one
# def create_download_thread(self, ...): ...
# def create_extraction_thread(self, ...): ...
# def create_hash_thread(self, ...): ...
def show_result(self):
"""显示安装结果调用patch_manager的show_result方法"""
self.patch_manager.show_result()
@@ -451,104 +446,35 @@ class MainWindow(QMainWindow):
self.shutdown_app(event)
def shutdown_app(self, event=None, force_exit=False):
"""关闭应用程序
Args:
event: 关闭事件如果是从closeEvent调用的
force_exit: 是否强制退出
"""
# 检查是否有动画或任务正在进行
"""关闭应用程序"""
if hasattr(self, 'animation_in_progress') and self.animation_in_progress and not force_exit:
# 如果动画正在进行,阻止退出
if event:
event.ignore()
return
# 检查是否有下载任务正在进行
if hasattr(self.download_manager, 'current_download_thread') and \
self.download_manager.current_download_thread and \
self.download_manager.current_download_thread.isRunning() and not force_exit:
# 询问用户是否确认退出
reply = QMessageBox.question(
self,
f"确认退出 - {APP_NAME}",
"\n下载任务正在进行中,确定要退出吗?\n",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.No:
if event:
event.ignore()
return
# 在退出前优雅地清理后台线程,避免 QThread 在运行中被销毁
def _graceful_stop(thread_obj, name="thread", timeout_ms=2000):
try:
if thread_obj and hasattr(thread_obj, 'isRunning') and thread_obj.isRunning():
# 首选等待自然结束
if hasattr(thread_obj, 'requestInterruption'):
try:
thread_obj.requestInterruption()
except Exception:
pass
thread_obj.wait(timeout_ms)
# 仍未退出时,最后手段终止
if thread_obj.isRunning():
try:
thread_obj.terminate()
except Exception:
pass
thread_obj.wait(1000)
except Exception:
pass
# 清理主窗口直接持有的线程
_graceful_stop(getattr(self, 'pre_hash_thread', None), 'pre_hash_thread')
_graceful_stop(getattr(self, 'hash_thread', None), 'hash_thread')
threads_to_stop = {
'pre_hash': getattr(self, 'pre_hash_thread', None),
'hash': getattr(self, 'hash_thread', None),
'offline_hash': getattr(self.offline_mode_manager, 'hash_thread', None),
'extraction': getattr(self.offline_mode_manager, 'extraction_thread', None),
'config_fetch': getattr(self.config_manager, 'config_fetch_thread', None),
'game_detector': getattr(self.game_detector, 'detection_thread', None),
'patch_check': getattr(self.patch_detector, 'patch_check_thread', None)
}
# Add current download thread if it's running
if hasattr(self.download_manager, 'current_download_thread') and self.download_manager.current_download_thread:
threads_to_stop['download'] = self.download_manager.current_download_thread
# 清理离线管理器中的线程
try:
if hasattr(self, 'offline_mode_manager') and self.offline_mode_manager:
_graceful_stop(getattr(self.offline_mode_manager, 'hash_thread', None), 'offline_hash_thread')
_graceful_stop(getattr(self.offline_mode_manager, 'extraction_thread', None), 'extraction_thread')
except Exception:
pass
self.download_manager.graceful_stop_threads(threads_to_stop)
# 清理配置获取线程
try:
if hasattr(self, 'config_manager') and hasattr(self.config_manager, 'config_fetch_thread'):
_graceful_stop(self.config_manager.config_fetch_thread, 'config_fetch_thread', 1000)
except Exception:
pass
# 清理游戏识别线程
try:
if hasattr(self, 'game_detector') and hasattr(self.game_detector, 'detection_thread'):
_graceful_stop(self.game_detector.detection_thread, 'detection_thread', 1000)
except Exception:
pass
# 清理补丁检查线程
try:
if hasattr(self, 'patch_detector') and hasattr(self.patch_detector, 'patch_check_thread'):
_graceful_stop(self.patch_detector.patch_check_thread, 'patch_check_thread', 1000)
except Exception:
pass
# 恢复hosts文件如果未禁用自动还原
self.download_manager.hosts_manager.restore()
# 额外检查并清理hosts文件中的残留记录如果未禁用自动还原
self.download_manager.hosts_manager.check_and_clean_all_entries()
# 停止日志记录
self.debug_manager.stop_logging()
if not force_exit:
reply = QMessageBox.question(
self,
f"确认退出 - {APP_NAME}",
"\n确定要退出吗?\n",
self, f"确认退出 - {APP_NAME}", "\n确定要退出吗?\n",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.No
)
@@ -557,7 +483,6 @@ class MainWindow(QMainWindow):
event.ignore()
return
# 退出应用程序
if event:
event.accept()
else:
@@ -635,7 +560,7 @@ class MainWindow(QMainWindow):
return
self.download_manager.selected_folder = self.selected_folder
self.show_loading_dialog("正在识别游戏目录...")
self.ui_manager.show_loading_dialog("正在识别游戏目录...")
self.setEnabled(False)
# 异步识别游戏目录
@@ -654,33 +579,8 @@ class MainWindow(QMainWindow):
# 版本正常,使用原有的下载流程
self.download_manager.file_dialog()
def show_loading_dialog(self, message):
"""显示加载对话框"""
if not self.loading_dialog:
self.loading_dialog = QDialog(self)
self.loading_dialog.setWindowTitle(f"请稍候 - {APP_NAME}")
self.loading_dialog.setFixedSize(300, 100)
self.loading_dialog.setModal(True)
layout = QVBoxLayout()
self.loading_label = QLabel(message)
self.loading_label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.loading_label)
self.loading_dialog.setLayout(layout)
else:
self.loading_label.setText(message)
self.loading_dialog.show()
QtWidgets.QApplication.processEvents()
def hide_loading_dialog(self):
"""隐藏加载对话框"""
if self.loading_dialog:
self.loading_dialog.hide()
self.loading_dialog = None
def on_game_directories_identified(self, game_dirs):
"""游戏目录识别完成后的回调"""
self.hide_loading_dialog()
self.ui_manager.hide_loading_dialog()
if not game_dirs:
self.setEnabled(True)
@@ -692,7 +592,7 @@ class MainWindow(QMainWindow):
)
return
self.show_loading_dialog("正在检查补丁状态...")
self.ui_manager.show_loading_dialog("正在检查补丁状态...")
install_paths = self.download_manager.get_install_paths()
@@ -709,8 +609,7 @@ class MainWindow(QMainWindow):
self.pre_hash_thread.start()
def on_pre_hash_finished(self, updated_status, game_dirs):
"""哈希预检查完成后的回调"""
self.hide_loading_dialog()
self.ui_manager.hide_loading_dialog()
self.setEnabled(True)
self.patch_detector.on_offline_pre_hash_finished(updated_status, game_dirs)
@@ -725,9 +624,32 @@ class MainWindow(QMainWindow):
try:
# 初始化离线模式管理器
if not hasattr(self, 'offline_mode_manager') or self.offline_mode_manager is None:
from core.offline_mode_manager import OfflineModeManager
from core.managers.offline_mode_manager import OfflineModeManager
self.offline_mode_manager = OfflineModeManager(self)
# 在调试模式下记录当前执行路径
is_debug_mode = self.config.get('debug_mode', False) if hasattr(self, 'config') else False
if is_debug_mode:
import os
import sys
current_dir = os.getcwd()
logger.debug(f"DEBUG: 当前工作目录: {current_dir}")
logger.debug(f"DEBUG: 是否为打包环境: {getattr(sys, 'frozen', False)}")
if getattr(sys, 'frozen', False):
logger.debug(f"DEBUG: 可执行文件路径: {sys.executable}")
# 尝试列出当前目录中的文件(调试用)
try:
files = os.listdir(current_dir)
logger.debug(f"DEBUG: 当前目录文件列表: {files}")
# 检查上级目录
parent_dir = os.path.dirname(current_dir)
parent_files = os.listdir(parent_dir)
logger.debug(f"DEBUG: 上级目录 {parent_dir} 文件列表: {parent_files}")
except Exception as e:
logger.debug(f"DEBUG: 列出目录文件时出错: {str(e)}")
# 扫描离线补丁文件
self.offline_mode_manager.scan_for_offline_patches()
@@ -774,6 +696,7 @@ class MainWindow(QMainWindow):
self.set_start_button_enabled(False)
logger.error(f"错误: 检查离线模式时发生异常: {e}")
logger.error(f"错误详情: {traceback.format_exc()}")
return False
def close_hash_msg_box(self):