2025-09-17 17:48:35 +08:00
|
|
|
|
#!/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
|
|
|
|
|
|
|
2025-09-18 15:52:03 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
2025-09-17 17:48:35 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
2025-09-18 15:52:03 +08:00
|
|
|
|
def create_multi_size_icon():
|
2025-09-17 17:48:35 +08:00
|
|
|
|
"""创建包含多种尺寸的QIcon对象"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
icon = QIcon()
|
|
|
|
|
|
|
|
|
|
|
|
# 我们有的图标文件
|
|
|
|
|
|
available_files = [
|
2025-09-18 15:52:03 +08:00
|
|
|
|
("static/ai_assistant_icon_16.png", 16),
|
|
|
|
|
|
("static/ai_assistant_icon_32.png", 32),
|
|
|
|
|
|
("static/ai_assistant_icon_64.png", 64),
|
2025-09-17 17:48:35 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
icon_loaded = False
|
2025-09-18 15:52:03 +08:00
|
|
|
|
for relative_path, size in available_files:
|
|
|
|
|
|
icon_path = get_resource_path(relative_path)
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if os.path.exists(icon_path):
|
|
|
|
|
|
icon.addFile(icon_path, QSize(size, size))
|
2025-09-18 15:52:03 +08:00
|
|
|
|
print(f"[INFO] 添加图标 {size}x{size}: {os.path.basename(icon_path)}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
icon_loaded = True
|
2025-09-18 15:52:03 +08:00
|
|
|
|
else:
|
|
|
|
|
|
print(f"[WARNING] 图标文件不存在: {icon_path}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
# 如果没有加载任何图标,尝试加载单个文件
|
|
|
|
|
|
if not icon_loaded:
|
2025-09-18 15:52:03 +08:00
|
|
|
|
fallback_path = get_resource_path("static/ai_assistant_icon_32.png")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if os.path.exists(fallback_path):
|
|
|
|
|
|
icon = QIcon(fallback_path)
|
|
|
|
|
|
print(f"[INFO] 使用备用图标: {fallback_path}")
|
2025-09-18 15:52:03 +08:00
|
|
|
|
icon_loaded = True
|
|
|
|
|
|
|
|
|
|
|
|
if not icon_loaded:
|
|
|
|
|
|
print("[WARNING] 没有找到任何图标文件,将使用系统默认图标")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
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_())
|