一、功能概述与实现思路
本方案通过PySide6实现两个增强功能:
功能介绍
- 系统托盘图标:当应用窗口最小化时,程序会驻留在系统托盘区域。用户可通过右键点击该图标,呼出包含多种操作选项的菜单,便于快捷操作。
- 桌面悬浮球:在关闭主界面后,系统会自动生成一个悬浮于桌面的小球。该悬浮球为用户提供了便捷的交互入口,可快速唤起隐藏的主界面。
实现架构:
bash
项目结构
├── resources/
│ ├── app_mini.ico # 悬浮球图标
│ └── app_tray.ico # 托盘图标
├── app_mini.py # 悬浮球实现
状态流转示意图:
悬浮球代码实现(app_mini.py)
python
import sys
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
from PySide6.QtGui import QMouseEvent, QPixmap, QGuiApplication
from PySide6.QtCore import Qt, QTimer
class FloatingBall(QWidget):
def __init__(self, main_window):
super().__init__()
# 设置悬浮球背景为透明,增强视觉效果
self.setStyleSheet("background-color: transparent;")
self.main_window = main_window
self.init_ui()
def init_ui(self):
# 设置窗口标志,使悬浮球无框、始终置顶且不显示在任务栏
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Tool)
# 设置悬浮球的大小
self.setGeometry(0, 0, 80, 80)
# 设置悬浮球的初始透明度
self.setWindowOpacity(0.8)
self.setup_background_image()
# 将悬浮球移动到屏幕右上角
self.move_to_top_right()
# 用于记录鼠标拖动时的位置
self.dragPosition = None
# 开启鼠标跟踪,以便处理鼠标移动事件
self.setMouseTracking(True)
# 启动呼吸灯效果,让悬浮球的透明度周期性变化
self.breathing_light_window()
def breathing_light_window(self):
# 初始透明度
self.opacity = 0.2
# 透明度每次变化的值,控制呼吸的速度和节奏
self.direction = 0.02
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_opacity)
# 设置定时器间隔为 50 毫秒,可根据需要调整呼吸节奏快慢
self.timer.start(50)
# 更新透明度
def update_opacity(self):
self.opacity += self.direction
if self.opacity >= 1.0:
self.direction = -0.02 # 达到最大透明度后开始减小透明度
elif self.opacity <= 0.2:
self.direction = 0.02 # 达到最小透明度后开始增大透明度
self.setWindowOpacity(self.opacity)
def setup_background_image(self):
layout = QVBoxLayout()
pixmap = QPixmap('resources/app_mini.ico')
pixmap = pixmap.scaled(self.size())
self.background_label = QLabel(self)
self.background_label.setPixmap(pixmap)
self.background_label.resize(self.size())
layout.addWidget(self.background_label)
self.setLayout(layout)
def move_to_top_right(self):
screen_geo = QGuiApplication.primaryScreen().geometry()
x = screen_geo.width() - self.width() - 10
y = 10
self.move(x, y)
def mousePressEvent(self, event: QMouseEvent):
if event.button() == Qt.MouseButton.LeftButton:
self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event: QMouseEvent):
if event.buttons() == Qt.MouseButton.LeftButton and self.dragPosition:
self.move(event.globalPos() - self.dragPosition)
event.accept()
# 鼠标释放
def mouseReleaseEvent(self, event: QMouseEvent):
if event.button() == Qt.MouseButton.LeftButton:
self.dragPosition = None
def show_main_window(self):
self.main_window.show()
self.main_window.is_floating_ball_visible = False
self.hide()
# 鼠标双击,打开主界面
def mouseDoubleClickEvent(self, event: QMouseEvent):
if event.button() == Qt.MouseButton.LeftButton:
self.show_main_window()
上述代码实现了一个具有透明背景的悬浮球。当主界面关闭时,会创建该悬浮球。用户双击悬浮球后,隐藏的主界面将重新显示。目前,悬浮球仅添加了呼吸灯效果,通过周期性地改变透明度,使其呈现出类似呼吸的动态效果。
主界面代码实现(main_window.py)
python
import sys
from PySide6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QSystemTrayIcon, QMenu
from PySide6.QtGui import QFont, QIcon, QAction
from app_mini import FloatingBall
from batch_file_renamer import RenameFileApp
class MainWindow(QWidget):
def __init__(self, tray_icon_visible=False):
super().__init__()
# 悬浮球可见状态,false可以创建悬浮球,反之。。。
self.is_floating_ball_visible = False
# 任务栏托盘标志位,False没有创建 True已创建
self.is_tray_icon_visible = tray_icon_visible
self.floating_ball = FloatingBall(self)
self.init_ui()
def init_ui(self):
self.setWindowTitle("PyQt示例应用")
self.setGeometry(100, 100, 300, 250)
self.setStyleSheet("background-color: #F5F5F5;") # 设置窗口背景色为淡灰色
layout = QVBoxLayout()
# 重命名使者
rename_file_btn = QPushButton("重命名使者")
rename_file_btn.setFont(QFont('Arial', 14))
rename_file_btn.setStyleSheet("""
QPushButton {
background-color: #9C27B0;
color: white;
border-radius: 8px;
padding: 10px;
}
QPushButton:hover {
background-color: #8E24AA;
}
""")
rename_file_btn.clicked.connect(self.rename_file_btn_clicked)
layout.addWidget(rename_file_btn)
self.setLayout(layout)
# 处理窗口关闭事件,使其最小化到托盘
self.closeEvent = self.handle_close_event
# 创建系统托盘图标
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(QIcon('resources/app_tray.ico')) # 这里需要一个名为icon.png的图标文件,可以替换为真实路径
self.tray_icon.activated.connect(self.tray_icon_activated)
# 创建托盘菜单
tray_menu = QMenu()
show_action = QAction("主界面", self)
show_action.triggered.connect(self.tray_menu_show_main)
quit_action = QAction("退出", self)
quit_action.triggered.connect(sys.exit)
tray_menu.addAction(show_action)
tray_menu.addAction(quit_action)
self.tray_icon.setContextMenu(tray_menu)
# 从托盘菜单点击显示窗口
def tray_menu_show_main(self):
self.show()
# 悬浮球退出
if self.is_floating_ball_visible:
self.floating_ball.close()
self.is_floating_ball_visible = False
# 处理窗口关闭事件
def handle_close_event(self, event):
event.ignore()
self.hide()
if not self.is_tray_icon_visible:
self.tray_icon.show()
self.is_tray_icon_visible = True
if not self.is_floating_ball_visible:
self.create_floating_ball()
def create_floating_ball(self):
self.floating_ball.show()
self.is_floating_ball_visible = True
# 双击托盘,打开窗口
def tray_icon_activated(self, reason):
if reason == QSystemTrayIcon.ActivationReason.DoubleClick:
self.show()
# 悬浮球退出
if self.is_floating_ball_visible:
self.floating_ball.close()
self.is_floating_ball_visible = False
def rename_file_btn_clicked(self):
print("按钮<重命名使者>被点击了")
self.rename_file = RenameFileApp()
self.rename_file.show()
在主界面代码中,当关闭窗口时,会创建悬浮球和系统托盘图标。系统托盘图标配备了右键菜单,提供了显示主界面和退出应用程序的功能。需要注意的是,每次关闭主界面时,都需要判断悬浮球和托盘图标是否已经创建。如果已经创建,只需将它们显示出来即可,避免重复创建,从而提高程序的性能和稳定性。
效果图如下:
附:代码<Github>