python制作桌宠
·
1. 导入模块部分
import os
import sys
import random
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
- 作用:导入程序依赖的模块。
os:用于文件路径处理(如拼接目录、判断文件是否存在)。sys:用于程序退出(sys.exit())。random:用于随机选择动画和对话内容。PyQt5相关模块:提供 GUI 组件(窗口、标签、托盘等)、核心功能(定时器、事件处理)和绘图支持(GIF 显示、图标等)。
2. 主类定义:DesktopPet(QWidget)
该类继承自QWidget(PyQt5 的基础窗口类),是整个桌面宠物的核心,包含所有功能实现。
3. 初始化方法:__init__
def __init__(self, parent=None, **kwargs):
super(DesktopPet, self).__init__(parent,** kwargs)
# 基础设置
self.scale_factor = 0.6 # 缩放比例
self.is_dragging = False # 拖动状态标记
# 路径设置
self.project_dir = r"C:\Users\30685\Desktop\py\蜡笔小新桌宠" # 项目根目录
self.normal_dir = os.path.join(self.project_dir, "normal") # 正常动画目录
self.click_dir = os.path.join(self.project_dir, "click") # 点击动画目录
# 文件路径
self.click_gif_path = os.path.join(self.click_dir, "click.gif")
self.default_gif_path = os.path.join(self.normal_dir, "normal1.gif")
self.tray_icon_path = os.path.join(self.normal_dir, "tigerIcon.jpg")
self.dialog_path = os.path.join(self.normal_dir, "dialog.txt")
# 初始化组件
self.init_window()
self.init_tray()
self.init_pet_resources()
self.init_interaction()
# 显示窗口
self.adjustSize()
self.random_position()
self.show()
- 作用:初始化桌面宠物的基础属性、资源路径,并调用其他初始化方法完成程序启动。
- 关键细节:
scale_factor:控制动画的缩放比例(0.6 表示缩小到原图的 60%)。- 路径设置:明确了程序依赖的资源文件(GIF 动画、图标、对话文本)的位置,需确保实际文件与路径对应,否则会报错。
- 初始化方法调用:通过
init_window等方法分模块初始化,代码结构清晰。 - 窗口显示:启动时随机位置显示,并自动调整大小。
4. 窗口基础设置:init_window
def init_window(self):
# 无边框、置顶、透明背景
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SubWindow)
self.setAutoFillBackground(False)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.repaint()
- 作用:设置窗口的基础样式,使其符合 “桌宠” 的视觉效果。
- 关键细节:
Qt.FramelessWindowHint:去除窗口边框(使桌宠看起来像独立的角色,而非传统窗口)。Qt.WindowStaysOnTopHint:窗口置顶(确保桌宠始终显示在其他窗口上方)。Qt.WA_TranslucentBackground:透明背景(避免 GIF 动画周围出现白色边框,提升融合感)。
5. 系统托盘设置:init_tray
def init_tray(self):
# 创建托盘菜单
self.tray_menu = QMenu(self)
font = QFont("SimHei") # 支持中文显示
self.tray_menu.setFont(font)
# 菜单动作
quit_action = QAction('退出', self, triggered=self.quit)
quit_action.setIcon(QIcon(self.tray_icon_path))
show_action = QAction('显示', self, triggered=self.show_window)
# 添加菜单动作
self.tray_menu.addAction(quit_action)
self.tray_menu.addAction(show_action)
# 初始化托盘
self.tray = QSystemTrayIcon(self)
self.tray.setIcon(QIcon(self.tray_icon_path))
self.tray.setContextMenu(self.tray_menu)
self.tray.show()
- 作用:创建系统托盘图标和右键菜单,方便用户操作(如退出程序、显示隐藏的桌宠)。
- 关键细节:
- 中文支持:通过
QFont("SimHei")设置字体,确保菜单中的中文正常显示。 - 托盘菜单功能:
- “退出”:调用
quit方法关闭程序。 - “显示”:调用
show_window方法恢复隐藏的桌宠。
- “退出”:调用
- 托盘图标:设置托盘显示的图标,增强辨识度。
- 中文支持:通过
6. 资源初始化:init_pet_resources
def init_pet_resources(self):
# 创建主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
# 图片标签(显示动画)
self.image_label = QLabel(self)
self.image_label.setAlignment(Qt.AlignCenter)
# 对话标签(显示文本)
self.talk_label = QLabel(self)
self.talk_label.setWordWrap(True)
self.talk_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
self.talk_label.setFont(QFont("KaiTi", 10))
self.talk_label.setStyleSheet("""
color: blue;
background-color: rgba(255,255,255,150);
padding: 5px;
border-radius: 3px;
""")
self.talk_label.setAlignment(Qt.AlignCenter)
# 添加到布局
main_layout.addWidget(self.image_label)
main_layout.addWidget(self.talk_label)
self.setLayout(main_layout)
# 加载对话内容和动画
self.load_dialogs()
self.load_normal_animations()
self.update_animation(self.default_gif_path)
- 作用:初始化显示动画和对话的 UI 组件,并加载资源文件。
- 关键细节:
- 布局管理:使用
QVBoxLayout(垂直布局),将动画标签(image_label)和对话标签(talk_label)上下排列。 - 对话标签样式:
WordWrap(True):文本自动换行(避免对话过长超出显示范围)。- 样式表:设置文本颜色(蓝色)、半透明背景(rgba (255,255,255,150))、内边距和圆角,使对话看起来像 “气泡”。
- 资源加载:调用
load_dialogs和load_normal_animations加载文本和动画资源,并默认显示normal1.gif。
- 布局管理:使用
7. 交互逻辑初始化:init_interaction
def init_interaction(self):
self.state = 0 # 0: 待机状态, 1: 点击/拖动状态
# 正常动画切换定时器(3秒一次)
self.normal_anim_timer = QTimer()
self.normal_anim_timer.timeout.connect(self.switch_normal_animation)
self.normal_anim_timer.start(3000)
# 对话切换定时器(5秒一次)
self.talk_timer = QTimer()
self.talk_timer.timeout.connect(self.update_talk)
self.talk_timer.start(5000)
# 初始对话
self.update_talk()
- 作用:初始化桌宠的自动交互逻辑(定时切换动画和对话)。
- 关键细节:
state:状态标记(0 = 待机,1 = 被点击 / 拖动),用于控制不同状态下的动画和对话显示。- 定时器(
QTimer):normal_anim_timer:3 秒触发一次,调用switch_normal_animation随机切换正常状态的动画。talk_timer:5 秒触发一次,调用update_talk随机切换对话内容。
8. 资源加载方法
load_dialogs(加载对话内容)
def load_dialogs(self):
self.dialogs = []
try:
with open(self.dialog_path, "r", encoding="utf-8") as f:
self.dialogs = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
self.dialogs = [
"你好呀!我是你的桌面宠物~",
"今天过得怎么样?",
"天气真好,适合出去走走呢!",
"拖动我可以改变位置哦~"
]
- 作用:从
dialog.txt文件加载对话文本,若文件不存在则使用默认对话。 - 关键细节:
- 容错处理:若
dialog.txt缺失,程序不会崩溃,而是使用预设的默认对话。 - 中文支持:打开文件时指定
encoding="utf-8",避免中文乱码。
- 容错处理:若
load_normal_animations(加载正常状态动画)
def load_normal_animations(self):
self.normal_gifs = []
if os.path.exists(self.normal_dir):
for file in os.listdir(self.normal_dir):
if file.lower().endswith(".gif") and "click" not in file.lower():
self.normal_gifs.append(os.path.join(self.normal_dir, file))
# 如果没有找到正常动画,使用默认动画
if not self.normal_gifs:
self.normal_gifs.append(self.default_gif_path)
- 作用:加载
normal目录下的所有 GIF 动画(排除包含 “click” 的文件,避免与点击动画混淆)。 - 关键细节:
- 筛选逻辑:只加载
.gif文件,且排除文件名含 “click” 的文件,确保正常状态动画的纯净性。 - 容错处理:若目录为空或无符合条件的文件,默认添加
normal1.gif,避免程序报错。
- 筛选逻辑:只加载
9. 动画和对话更新方法
update_animation(核心动画显示方法)
def update_animation(self, gif_path):
# 检查文件是否存在
if not os.path.exists(gif_path):
print(f"警告: 动画文件不存在 - {gif_path}")
return
# 创建QMovie对象
self.movie = QMovie(gif_path)
if not self.movie.isValid():
print(f"警告: 无法加载动画 - {gif_path}")
return
# 获取原始尺寸并等比例缩放
original_rect = self.movie.frameRect()
original_width = original_rect.width()
original_height = original_rect.height()
# 容错处理
if original_width <= 0 or original_height <= 0:
original_width, original_height = 200, 200
# 计算缩放后尺寸
scaled_width = int(original_width * self.scale_factor)
scaled_height = int(original_height * self.scale_factor)
# 应用缩放并显示
self.movie.setScaledSize(QSize(scaled_width, scaled_height))
self.image_label.setMovie(self.movie)
self.movie.start()
# 调整对话标签宽度
self.talk_label.setMaximumWidth(scaled_width + 20)
- 作用:加载并显示指定路径的 GIF 动画,并按比例缩放。
- 关键细节:
- 文件检查:先判断 GIF 文件是否存在、是否有效,避免因资源缺失导致程序异常。
- 缩放逻辑:根据
scale_factor计算缩放后的尺寸,确保动画大小统一且符合预期。 - 对话标签适配:根据动画宽度调整对话标签的最大宽度,避免对话文本过长超出动画范围。
switch_normal_animation(切换正常动画)
def switch_normal_animation(self):
if self.state == 0 and self.normal_gifs: # 只有在待机状态才切换
random_gif = random.choice(self.normal_gifs)
self.update_animation(random_gif)
- 作用:在待机状态下(
state=0)随机切换正常动画,增加动态感。
update_talk(更新对话内容)
def update_talk(self):
if self.state == 0 and self.dialogs: # 待机状态
self.talk_label.setText(random.choice(self.dialogs))
else: # 点击/拖动状态
self.talk_label.setText("正在拖动我呢~")
self.talk_label.adjustSize()
self.adjustSize()
- 作用:根据当前状态更新对话内容(待机时随机显示预设对话,拖动时显示固定文本)。
10. 鼠标交互事件(拖动和点击响应)
mousePressEvent(鼠标按下时)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.is_dragging = True
self.drag_start_pos = event.globalPos() - self.pos()
# 切换到点击状态并播放点击动画
self.state = 1
self.update_talk() # 更新对话
self.update_animation(self.click_gif_path) # 显示click.gif
event.accept()
- 作用:响应鼠标左键按下事件,开始拖动并切换到 “点击状态”。
- 关键细节:
- 记录拖动起点:
drag_start_pos用于计算鼠标移动时窗口的新位置。 - 状态切换:
state设为 1,同时更新对话(显示 “正在拖动我呢~”)和动画(显示click.gif)。
- 记录拖动起点:
mouseMoveEvent(鼠标移动时)
def mouseMoveEvent(self, event):
if self.is_dragging and event.buttons() & Qt.LeftButton:
# 拖动过程中保持点击状态和click.gif
self.move(event.globalPos() - self.drag_start_pos)
event.accept()
- 作用:响应鼠标移动事件,实现窗口拖动功能(根据鼠标位置计算窗口新坐标)。
mouseReleaseEvent(鼠标释放时)
def mouseReleaseEvent(self, event):
if self.is_dragging:
self.is_dragging = False
# 释放鼠标后恢复待机状态
self.state = 0
self.update_talk()
self.switch_normal_animation() # 切换回正常动画
event.accept()
- 作用:响应鼠标释放事件,结束拖动并恢复 “待机状态”(切换回正常动画和随机对话)。
11. 其他辅助方法
random_position:程序启动时随机设置窗口在屏幕上的位置(避免每次都显示在同一个地方)。quit:退出程序(关闭窗口并终止应用)。show_window:从隐藏状态恢复窗口(将透明度设为 1 并显示)。contextMenuEvent:右键菜单(提供 “隐藏” 和 “退出” 选项,隐藏时窗口透明度设为 0)。
12. 程序入口
if __name__ == '__main__':
# 确保中文显示正常
app = QApplication(sys.argv)
app.setFont(QFont("SimHei", 10))
# 创建并运行宠物
pet = DesktopPet()
sys.exit(app.exec_())
- 作用:启动程序,初始化应用实例并创建
DesktopPet对象,进入事件循环。 - 关键细节:
app.setFont(QFont("SimHei", 10))确保全局中文显示正常(避免菜单、对话等文本乱码)。
总结
这段代码通过 PyQt5 实现了一个功能完整的桌面宠物程序,核心特点包括:
- 视觉效果:无边框、透明背景、置顶显示,使桌宠与桌面自然融合。
- 交互功能:支持鼠标拖动(改变位置)、点击响应(切换动画和对话)。
- 自动行为:定时切换动画和对话,提升生动感。
- 用户操作:系统托盘和右键菜单提供退出、隐藏等功能,方便管理。
使用时需注意:确保normal和click目录下有对应的 GIF 动画、图标和对话文件,路径与代码中的设置一致,否则可能出现资源加载失败的问题。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)