# main.py """主程序入口 — PySide6 版本""" import sys import os import traceback import warnings import logging from datetime import datetime # 必须在导入任何 matplotlib 之前设置后端 import matplotlib matplotlib.use('QtAgg') from PySide6.QtWidgets import QApplication, QMessageBox from PySide6.QtCore import Qt from license_utils import check_license from styles import apply_app_style # 屏蔽多余警告 warnings.filterwarnings('ignore') logging.getLogger("pymodbus").setLevel(logging.ERROR) # 优化 matplotlib 设置 matplotlib.rcParams['figure.max_open_warning'] = 20 matplotlib.rcParams['axes.linewidth'] = 0.5 matplotlib.rcParams['lines.linewidth'] = 1.0 # 中文字体 import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = [ 'Microsoft YaHei', 'SimHei', 'PingFang SC', 'Heiti TC', 'sans-serif' ] plt.rcParams['axes.unicode_minus'] = False # ---- 全局异常日志(打包为 exe 后排查问题用) ---- _LOG_DIR = os.path.join(os.path.dirname(sys.executable), "logs") os.makedirs(_LOG_DIR, exist_ok=True) _LOG_FILE = os.path.join(_LOG_DIR, f"reinloop_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") def _write_log(msg: str): try: with open(_LOG_FILE, "a", encoding="utf-8") as f: f.write(f"[{datetime.now().strftime('%H:%M:%S.%f')[:-3]}] {msg}\n") except Exception: pass def _global_excepthook(exc_type, exc_value, exc_tb): """未捕获异常 → 写日志 + 弹窗""" err = "".join(traceback.format_exception(exc_type, exc_value, exc_tb)) _write_log(f"未捕获异常:\n{err}") try: QMessageBox.critical(None, "程序错误", f"发生未捕获异常:\n{exc_value}\n\n详情见: {_LOG_FILE}") except Exception: pass sys.__excepthook__(exc_type, exc_value, exc_tb) def main(): """主程序入口""" sys.excepthook = _global_excepthook _write_log(f"启动 | Python={sys.version} | exe={sys.executable}") print("正在启动控制系统...") # 0. 防止 Windows 深色模式干扰 Qt 样式(打包后常见黑底问题) if sys.platform == "win32": os.environ.setdefault("QT_QPA_PLATFORM", "windows:darkmode=0") # 1. 初始化 QApplication app = QApplication(sys.argv) app.setApplicationName("ReinLoop") # 1.1 强制浅色模式(防止系统深色模式或 style 插件缺失导致黑底) app.setStyle("Fusion") # Fusion 内置于 QtCore,不依赖外部 style 插件 try: app.styleHints().setColorScheme(Qt.ColorScheme.Light) except (AttributeError, TypeError): pass # Qt < 6.5 无此方法,忽略 # 2. 在导入 UI 前完成许可证校验。UI 导入的 `api` 模块会读取已验证 # 许可证中的 device_id,因此撤销状态和设备心跳会使用同一个设备标识。 check_license() # 3. 应用全局样式 colors = apply_app_style(app) _write_log("样式加载完成") # 延迟导入,避免 `api` 在许可证校验前缓存默认 device_id。 from ui.main_window import MainWindow # 4. 创建主窗口 window = MainWindow(colors) _write_log("主窗口创建完成") window.show() # 5. 进入事件循环 _write_log("进入事件循环") sys.exit(app.exec()) if __name__ == '__main__': main()