PySide6 项目开发全攻略:托盘图标&悬浮球

一、功能概述与实现思路

本方案通过PySide6实现两个增强功能:

功能介绍

  1. 系统托盘图标:当应用窗口最小化时,程序会驻留在系统托盘区域。用户可通过右键点击该图标,呼出包含多种操作选项的菜单,便于快捷操作。
  2. 桌面悬浮球:在关闭主界面后,系统会自动生成一个悬浮于桌面的小球。该悬浮球为用户提供了便捷的交互入口,可快速唤起隐藏的主界面。

实现架构:

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>

相关推荐
√尖尖角↑25 分钟前
力扣——【104. 二叉树的最大深度】
python·算法·leetcode
小涵3 小时前
Python和JavaScript在字符串比较上的差异
开发语言·javascript·python
运维小文4 小时前
python文本处理-基础篇
开发语言·python·正则表达式
GodGump7 小时前
DeepSeek开源多模态大模型Janus-Pro部署
python
码界筑梦坊10 小时前
基于Flask的当当网畅销图书榜单可视化分析系统的设计与实现
后端·python·flask·毕业设计
m0_7482329210 小时前
纯 Python、Django、FastAPI、Flask、Pyramid、Jupyter、dbt 解析和差异分析
python·django·fastapi
测试杂货铺11 小时前
Jmeter常用的几种断言方法
自动化测试·软件测试·python·测试工具·jmeter·职场和发展·压力测试
WANGWUSAN6611 小时前
Python教程:使用Matplotlib模块画柱状图、饼形图、直方图
开发语言·经验分享·python·程序人生·matplotlib·数据可视化
Channing Lewis11 小时前
flask开发的网站,后端服务关闭后,可以找回之前的数据的吗
python·flask
莫问alicia12 小时前
苍穹外卖 项目记录 day11 Spring Task订单定时处理-来单提醒-客户催单
java·数据库·spring boot·python·spring·mybatis