325 lines
12 KiB
Python
325 lines
12 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
系统托盘功能测试脚本
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import logging
|
|
from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QWidget, QPushButton, QVBoxLayout, QLabel
|
|
from PyQt6.QtGui import QIcon
|
|
from PyQt6.QtCore import Qt
|
|
|
|
# 配置日志
|
|
logging.basicConfig(
|
|
level=logging.DEBUG,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.StreamHandler(),
|
|
logging.FileHandler('tray_test.log', encoding='utf-8')
|
|
]
|
|
)
|
|
logger = logging.getLogger('TrayTest')
|
|
|
|
class TrayTestWindow(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.init_ui()
|
|
self.create_tray_icon()
|
|
|
|
def init_ui(self):
|
|
"""初始化UI"""
|
|
self.setWindowTitle('系统托盘测试')
|
|
self.setGeometry(300, 300, 400, 300)
|
|
|
|
layout = QVBoxLayout()
|
|
|
|
# 添加说明标签
|
|
label = QLabel('这是一个系统托盘功能测试程序。关闭窗口后,应用程序将最小化到系统托盘。')
|
|
label.setWordWrap(True)
|
|
layout.addWidget(label)
|
|
|
|
# 添加测试按钮
|
|
self.show_message_button = QPushButton('显示托盘消息')
|
|
self.show_message_button.clicked.connect(self.test_show_message)
|
|
layout.addWidget(self.show_message_button)
|
|
|
|
self.toggle_icon_button = QPushButton('切换托盘图标')
|
|
self.toggle_icon_button.clicked.connect(self.test_toggle_icon)
|
|
layout.addWidget(self.toggle_icon_button)
|
|
|
|
self.quit_button = QPushButton('退出应用程序')
|
|
self.quit_button.clicked.connect(self.quit_application)
|
|
layout.addWidget(self.quit_button)
|
|
|
|
self.setLayout(layout)
|
|
|
|
def create_tray_icon(self):
|
|
"""创建系统托盘图标"""
|
|
logger.info("创建系统托盘图标")
|
|
|
|
# 检查系统是否支持系统托盘
|
|
if not QSystemTrayIcon.isSystemTrayAvailable():
|
|
logger.error("系统不支持系统托盘功能")
|
|
return False
|
|
|
|
try:
|
|
# 创建一个永久存在的QWidget作为托盘图标的父对象
|
|
self._tray_parent = QWidget()
|
|
self._tray_parent.setVisible(False)
|
|
|
|
# 创建系统托盘图标
|
|
self.tray_icon = QSystemTrayIcon(self._tray_parent)
|
|
|
|
# 创建托盘菜单
|
|
self.tray_menu = QMenu()
|
|
|
|
# 添加菜单项
|
|
self.show_action = self.tray_menu.addAction("显示窗口")
|
|
self.show_action.triggered.connect(self.show_and_activate)
|
|
|
|
self.tray_menu.addSeparator()
|
|
|
|
self.test_message_action = self.tray_menu.addAction("测试托盘消息")
|
|
self.test_message_action.triggered.connect(self.test_show_message)
|
|
|
|
self.test_icon_action = self.tray_menu.addAction("测试切换图标")
|
|
self.test_icon_action.triggered.connect(self.test_toggle_icon)
|
|
|
|
self.tray_menu.addSeparator()
|
|
|
|
self.quit_action = self.tray_menu.addAction("退出")
|
|
self.quit_action.triggered.connect(self.quit_application)
|
|
|
|
# 设置托盘菜单
|
|
self.tray_icon.setContextMenu(self.tray_menu)
|
|
|
|
# 设置图标
|
|
# 尝试使用系统图标
|
|
self.icon1 = QIcon.fromTheme("dialog-information")
|
|
self.icon2 = QIcon.fromTheme("dialog-warning")
|
|
|
|
# 如果系统图标不可用,使用标准图标
|
|
if self.icon1.isNull():
|
|
self.icon1 = self.style().standardIcon(self.style().StandardPixmap.SP_DialogApplyButton)
|
|
if self.icon2.isNull():
|
|
self.icon2 = self.style().standardIcon(self.style().StandardPixmap.SP_DialogWarningButton)
|
|
|
|
# 设置初始图标
|
|
self.tray_icon.setIcon(self.icon1)
|
|
self.current_icon = 1
|
|
|
|
# 连接托盘图标的激活信号
|
|
self.tray_icon.activated.connect(self.on_tray_activated)
|
|
|
|
# 显示托盘图标
|
|
self.tray_icon.show()
|
|
|
|
# 显示启动消息
|
|
self.show_tray_message("系统托盘测试", "应用程序已启动并显示在系统托盘")
|
|
|
|
logger.info("系统托盘图标创建完成")
|
|
return True
|
|
except Exception as e:
|
|
logger.exception(f"创建系统托盘图标失败: {str(e)}")
|
|
return False
|
|
|
|
def show_tray_message(self, title, message, icon_type="info", duration=2000):
|
|
"""显示系统托盘消息"""
|
|
if not hasattr(self, 'tray_icon') or self.tray_icon is None:
|
|
logger.error(f"无法显示托盘消息: {title} - {message}")
|
|
return False
|
|
|
|
logger.info(f"显示托盘消息: {title} - {message}")
|
|
|
|
# 设置图标类型
|
|
icon = None
|
|
try:
|
|
# 尝试使用枚举值 (PyQt6 6.0.0+)
|
|
if icon_type == "info":
|
|
icon = QSystemTrayIcon.MessageIcon.Information
|
|
elif icon_type == "warning":
|
|
icon = QSystemTrayIcon.MessageIcon.Warning
|
|
elif icon_type == "error":
|
|
icon = QSystemTrayIcon.MessageIcon.Critical
|
|
else:
|
|
icon = QSystemTrayIcon.MessageIcon.Information
|
|
except:
|
|
# 尝试使用整数值 (旧版PyQt6)
|
|
try:
|
|
if icon_type == "info":
|
|
icon = QSystemTrayIcon.Information
|
|
elif icon_type == "warning":
|
|
icon = QSystemTrayIcon.Warning
|
|
elif icon_type == "error":
|
|
icon = QSystemTrayIcon.Critical
|
|
else:
|
|
icon = QSystemTrayIcon.Information
|
|
except:
|
|
# 使用整数值
|
|
if icon_type == "info":
|
|
icon = 1 # Information
|
|
elif icon_type == "warning":
|
|
icon = 2 # Warning
|
|
elif icon_type == "error":
|
|
icon = 3 # Critical
|
|
else:
|
|
icon = 1 # Information
|
|
|
|
# 尝试显示消息
|
|
try:
|
|
self.tray_icon.showMessage(title, message, icon, duration)
|
|
return True
|
|
except Exception as e:
|
|
logger.exception(f"显示托盘消息失败: {str(e)}")
|
|
|
|
# 尝试使用整数值作为图标类型
|
|
try:
|
|
# 将枚举转换为整数
|
|
if isinstance(icon, object) and hasattr(icon, "value"):
|
|
icon_int = icon.value
|
|
else:
|
|
icon_int = 1 # 默认为Information
|
|
|
|
self.tray_icon.showMessage(title, message, icon_int, duration)
|
|
return True
|
|
except Exception as e2:
|
|
logger.exception(f"使用整数值显示托盘消息也失败: {str(e2)}")
|
|
return False
|
|
|
|
def on_tray_activated(self, reason):
|
|
"""处理托盘图标激活事件"""
|
|
logger.info(f"托盘图标被激活,原因: {reason}")
|
|
|
|
try:
|
|
# 获取激活原因的枚举值
|
|
try:
|
|
# 尝试使用枚举值 (PyQt6 6.0.0+)
|
|
double_click = QSystemTrayIcon.ActivationReason.DoubleClick
|
|
trigger = QSystemTrayIcon.ActivationReason.Trigger
|
|
except:
|
|
# 尝试使用整数值 (旧版PyQt6)
|
|
try:
|
|
double_click = QSystemTrayIcon.DoubleClick
|
|
trigger = QSystemTrayIcon.Trigger
|
|
except:
|
|
# 使用整数值
|
|
double_click = 2 # DoubleClick
|
|
trigger = 3 # Trigger
|
|
|
|
# 处理双击事件
|
|
if reason == double_click:
|
|
logger.info("托盘图标被双击,显示主窗口")
|
|
self.show_and_activate()
|
|
# 处理单击事件
|
|
elif reason == trigger:
|
|
logger.info("托盘图标被单击")
|
|
# 在某些系统上,单击可能不会自动显示上下文菜单
|
|
except Exception as e:
|
|
logger.exception(f"处理托盘图标激活事件失败: {str(e)}")
|
|
|
|
def show_and_activate(self):
|
|
"""显示并激活窗口"""
|
|
logger.info("显示并激活窗口")
|
|
self.show()
|
|
self.setWindowState(self.windowState() & ~Qt.WindowState.WindowMinimized)
|
|
self.activateWindow()
|
|
|
|
def test_show_message(self):
|
|
"""测试显示托盘消息"""
|
|
logger.info("测试显示托盘消息")
|
|
self.show_tray_message(
|
|
"测试消息",
|
|
"这是一条测试消息,用于验证系统托盘通知功能是否正常工作。",
|
|
"info"
|
|
)
|
|
|
|
def test_toggle_icon(self):
|
|
"""测试切换托盘图标"""
|
|
logger.info("测试切换托盘图标")
|
|
if not hasattr(self, 'tray_icon') or self.tray_icon is None:
|
|
logger.error("托盘图标不存在,无法切换图标")
|
|
return
|
|
|
|
try:
|
|
if self.current_icon == 1:
|
|
self.tray_icon.setIcon(self.icon2)
|
|
self.current_icon = 2
|
|
self.show_tray_message("图标已切换", "当前使用警告图标")
|
|
else:
|
|
self.tray_icon.setIcon(self.icon1)
|
|
self.current_icon = 1
|
|
self.show_tray_message("图标已切换", "当前使用信息图标")
|
|
except Exception as e:
|
|
logger.exception(f"切换托盘图标失败: {str(e)}")
|
|
|
|
def quit_application(self):
|
|
"""退出应用程序"""
|
|
logger.info("退出应用程序")
|
|
|
|
try:
|
|
# 隐藏托盘图标
|
|
if hasattr(self, 'tray_icon') and self.tray_icon is not None:
|
|
logger.info("隐藏托盘图标")
|
|
self.tray_icon.hide()
|
|
|
|
# 退出应用程序
|
|
logger.info("调用QApplication.quit()")
|
|
QApplication.quit()
|
|
except Exception as e:
|
|
logger.exception(f"退出应用程序失败: {str(e)}")
|
|
# 强制退出
|
|
QApplication.exit(1)
|
|
|
|
def closeEvent(self, event):
|
|
"""处理窗口关闭事件"""
|
|
logger.info("处理窗口关闭事件")
|
|
|
|
try:
|
|
# 如果系统托盘可用且托盘图标已创建,则最小化到系统托盘
|
|
if (QSystemTrayIcon.isSystemTrayAvailable() and
|
|
hasattr(self, 'tray_icon') and
|
|
self.tray_icon is not None and
|
|
self.tray_icon.isVisible()):
|
|
|
|
logger.info("最小化到系统托盘")
|
|
|
|
# 显示提示消息
|
|
self.show_tray_message(
|
|
"系统托盘测试",
|
|
"应用程序已最小化到系统托盘,双击托盘图标可以重新显示窗口"
|
|
)
|
|
|
|
# 隐藏主窗口
|
|
self.hide()
|
|
|
|
# 忽略关闭事件,防止应用程序退出
|
|
event.ignore()
|
|
else:
|
|
# 系统托盘不可用,正常关闭应用程序
|
|
logger.info("系统托盘不可用,正常关闭应用程序")
|
|
event.accept()
|
|
except Exception as e:
|
|
logger.exception(f"处理窗口关闭事件失败: {str(e)}")
|
|
# 出现异常时,默认接受关闭事件
|
|
event.accept()
|
|
|
|
def main():
|
|
"""主函数"""
|
|
logger.info("应用程序启动")
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
# 设置应用程序不会在最后一个窗口关闭时退出
|
|
app.setQuitOnLastWindowClosed(False)
|
|
|
|
window = TrayTestWindow()
|
|
window.show()
|
|
|
|
sys.exit(app.exec())
|
|
|
|
if __name__ == "__main__":
|
|
main()
|