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>

相关推荐
陈随易8 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
用户83562907805112 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
用户83562907805112 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
这个DBA有点耶14 小时前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
Larcher15 小时前
从零搭建 MCP 服务——让 AI 拥有无限扩展能力
人工智能·程序员
SamDeepThinking16 小时前
从源码到代码:MyBatis-Flex 与 MyBatis-Plus 的逐项对比
java·后端·程序员
AskHarries19 小时前
用 OpenClaw 处理表格:清洗 Excel、生成图表和分析结论
程序员
爱勇宝19 小时前
Claude Code 被曝暗藏“隐形检测”代码:封代理不是最可怕的,可怕的是你根本不知道它在干什么
前端·后端·程序员
触底反弹20 小时前
🔥 2026 年爆火的 Harness Engineering 到底是什么?从原理到实战一文讲透
javascript·人工智能·程序员