#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Windows任务栏图标修复模块 解决PyQt5应用在任务栏显示Python图标的问题 """ import os import sys from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtCore import QSize def get_resource_path(relative_path): """获取资源文件的绝对路径,兼容开发环境和PyInstaller打包环境""" try: # PyInstaller打包后的环境 if getattr(sys, 'frozen', False): # 获取可执行文件目录 exe_dir = os.path.dirname(sys.executable) # 检查新版PyInstaller的_internal目录结构 internal_dir = os.path.join(exe_dir, "_internal") if os.path.exists(internal_dir): # 新版PyInstaller: exe在外面,资源在_internal里 base_path = internal_dir print(f"[INFO] 检测到PyInstaller _internal 结构: {internal_dir}") else: # 老版PyInstaller或onefile模式 if hasattr(sys, '_MEIPASS'): # 一次性临时解压目录 base_path = sys._MEIPASS print(f"[INFO] 使用PyInstaller临时解压目录: {base_path}") else: # 直接exe目录 base_path = exe_dir print(f"[INFO] 使用exe目录: {base_path}") else: # 开发环境:需要智能判断项目根目录 script_dir = os.path.dirname(os.path.abspath(__file__)) # 检查当前目录是否包含static文件夹(即为项目根目录) if os.path.exists(os.path.join(script_dir, "static")): base_path = script_dir print(f"[INFO] 开发环境基础路径(当前目录): {base_path}") else: # 如果当前目录没有static,尝试上级目录 parent_dir = os.path.dirname(script_dir) if os.path.exists(os.path.join(parent_dir, "static")): base_path = parent_dir print(f"[INFO] 开发环境基础路径(上级目录): {base_path}") else: # 如果都找不到,默认使用当前目录 base_path = script_dir print(f"[INFO] 开发环境基础路径(默认当前): {base_path}") # 组合完整路径 full_path = os.path.join(base_path, relative_path) print(f"[INFO] 资源路径: {relative_path} -> {full_path}") return full_path except Exception as e: print(f"[ERROR] 获取资源路径失败: {e}") return relative_path def set_windows_app_id(app_id="ShuidropAI.CustomerService.1.0"): """设置Windows应用程序用户模型ID""" try: import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id) print(f"[INFO] Windows应用ID已设置: {app_id}") return True except Exception as e: print(f"[WARNING] 设置Windows应用ID失败: {e}") return False def create_multi_size_icon(): """创建包含多种尺寸的QIcon对象""" try: icon = QIcon() # 我们有的图标文件 available_files = [ ("static/ai_assistant_icon_16.png", 16), ("static/ai_assistant_icon_32.png", 32), ("static/ai_assistant_icon_64.png", 64), ] icon_loaded = False for relative_path, size in available_files: icon_path = get_resource_path(relative_path) if os.path.exists(icon_path): icon.addFile(icon_path, QSize(size, size)) print(f"[INFO] 添加图标 {size}x{size}: {os.path.basename(icon_path)}") icon_loaded = True else: print(f"[WARNING] 图标文件不存在: {icon_path}") # 如果没有加载任何图标,尝试加载单个文件 if not icon_loaded: fallback_path = get_resource_path("static/ai_assistant_icon_32.png") if os.path.exists(fallback_path): icon = QIcon(fallback_path) print(f"[INFO] 使用备用图标: {fallback_path}") icon_loaded = True if not icon_loaded: print("[WARNING] 没有找到任何图标文件,将使用系统默认图标") return icon except Exception as e: print(f"[ERROR] 创建多尺寸图标失败: {e}") return QIcon() def setup_windows_taskbar_icon(app, window=None): """完整设置Windows任务栏图标""" print("[INFO] 开始设置Windows任务栏图标...") # 1. 设置应用程序唯一ID set_windows_app_id() # 2. 创建多尺寸图标 icon = create_multi_size_icon() # 3. 设置应用程序级别图标 app.setWindowIcon(icon) print("[INFO] 应用程序图标已设置") # 4. 如果提供了窗口,也设置窗口图标 if window: window.setWindowIcon(icon) print("[INFO] 窗口图标已设置") # 5. 强制刷新应用程序图标缓存 try: if window and hasattr(window, 'winId'): # 等待窗口完全初始化 from PyQt5.QtCore import QTimer def delayed_icon_refresh(): try: window.setWindowIcon(icon) print("[INFO] 已延迟刷新窗口图标") except Exception as e: print(f"[WARNING] 延迟图标刷新失败: {e}") # 延迟100ms再次设置图标 QTimer.singleShot(100, delayed_icon_refresh) except Exception as e: print(f"[WARNING] 图标刷新失败: {e}") print("[INFO] Windows任务栏图标设置完成") return icon if __name__ == "__main__": # 测试模块 from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel app = QApplication(sys.argv) window = QMainWindow() window.setWindowTitle("任务栏图标测试") window.setCentralWidget(QLabel("测试Windows任务栏图标")) # 设置任务栏图标 setup_windows_taskbar_icon(app, window) window.show() sys.exit(app.exec_())