admin管理员组文章数量:1437030
做了一只哈基米桌宠
“在某个加班到深夜的晚上,我望着一成不变的桌面,心想:如果这儿有只可爱的小猫在走来走去、还能冲我眨眼,是不是整个编程体验都能变得柔和一些?”
一、灵感的诞生
小时候的电脑里,总有些奇奇怪怪又让人爱不释手的玩意儿,比如能陪你聊天的微软小助手 Clippy,或者是蹦来蹦去的小浣熊宠物。如今虽然操作系统越来越精简高效,但也未免显得太过冷清了。
这篇文章,记录了我如何用 PyQt 打造出一款“现代桌面宠物”的完整旅程。它不是玩具,也不是纯粹的代码练习,而是一次结合 GUI、动画、透明窗口、多线程、文件管理、逻辑控制等诸多知识点的 桌面宠物开发实战。
而最重要的是,它真的能在你电脑上“活起来”。
二、项目构思与功能概览
我打算做一只可以:
- 在桌面自由走动的小猫咪(随机移动)
- 可以通过右键菜单进行交互(喂食、聊天、换衣服等)
- 能根据时间段变换状态(比如深夜就犯困)
- 点击会有反应(如喵一声或弹出提示)
- 自带优雅的启动动画、灵动的 UI 与换肤支持
为了更直观地理清楚流程,我画了一张最初的功能模块图:
这个架构并不复杂,但覆盖的技术点很多,需要我们精细地设计每一个细节。
三、环境准备与基础设置
首先,确定技术栈与开发环境:
- 语言:Python 3.11+(看自己)
- GUI 框架:PyQt5(稳定成熟)
- 开发工具:PyCharm + QSS 样式 + 动图资源 + 图床(演示图像)
- 依赖库:
PyQt5
pygame
(用于音效播放)QMovie
(用于动态 gif 播放)
安装基础库
代码语言:bash复制pip install PyQt5 pygame
准备好环境后,我们就可以动手构建窗口。
四、打造“透明贴图窗口”
一个桌面宠物的核心,就是它必须“漂浮”在桌面上,并且没有任何系统边框。于是我们需要创建一个 无边框+透明背景 的窗口。
创建主窗口
代码语言:python代码运行次数:0运行复制from PyQt5.QtWidgets import QApplication, QLabel, QWidget
from PyQt5.QtGui import QMovie
from PyQt5.QtCore import Qt, QTimer, QPoint
import sys
class PetWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowFlags(Qt.FramelessWindowHint |
Qt.WindowStaysOnTopHint |
Qt.Tool) # 无边框、置顶、不出现在任务栏
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.label = QLabel(self)
self.movie = QMovie("assets/cat_idle.gif")
self.label.setMovie(self.movie)
self.movie.start()
self.resize(self.movie.currentPixmap().size())
self.setMouseTracking(True)
self.offset = None # 拖动支持
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.offset = event.pos()
def mouseMoveEvent(self, event):
if self.offset:
self.move(self.pos() + event.pos() - self.offset)
def mouseReleaseEvent(self, event):
self.offset = None
if __name__ == "__main__":
app = QApplication(sys.argv)
pet = PetWidget()
pet.show()
sys.exit(app.exec_())
这段代码完成了以下功能:
- 创建一个透明窗口
- 播放 gif 动画(作为宠物形象)
- 支持点击拖动窗口
- 始终置顶显示
至此,一只“傻乎乎地站着”的猫咪已经出现在桌面上了。
接下来,我要带着这只“逛桌面”的小猫,教你如何让它“活”起来——会自己闲逛、会打盹、还会偶尔伸个懒腰。要实现这些,我们需要一个状态机来管理宠物的各种行为,然后再用定时器驱动动画切换与位置更新。
五、宠物行为状态机与随机漫步
设计思路
我希望猫猫能以“吟游诗人”的姿态漫步桌面:有时候它在窗边打个盹,有时候它闲庭信步,还会不经意地伸个懒腰。于是我给它规划了三个主要状态:
- 闲逛(Idle):猫在当前坐标上下左右小范围游走。
- 打盹(Sleep):猫在某个固定位置静止,并播放打盹动画。
- 伸懒腰(Stretch):偶尔一次,从打盹切换到伸腰动画后再回到闲逛。
描绘一下这个状态机的样子:
这个状态机很简单,但能让猫猫显得生动。接下来,我们要用 Python + PyQt 的定时器来驱动它。
实现状态机
首先,在 PetWidget
类中增加一个内部状态管理器和定时器:
import random
from PyQt5.QtCore import QTimer, QRect
class PetWidget(QWidget):
def __init__(self):
# … 前面透明窗口与动画设置不变 …
# --- 行为状态机 ---
self.state = "Idle" # 当前状态
self.energy = 100 # “精力”值,下降到0时进入 Sleep
self.state_timer = QTimer() # 驱动状态逻辑
self.state_timer.timeout.connect(self.update_state)
self.state_timer.start(500) # 每 0.5s 调度一次
# 位置与移动
self.move_timer = QTimer() # 用于平滑移动
self.move_timer.timeout.connect(self.random_walk)
self.move_timer.start(50) # 每 0.05s 更新坐标
def update_state(self):
"""根据当前状态和条件切换行为状态,并更新对应动画。"""
if self.state == "Idle":
self.energy -= 1
# 当精力耗尽,进入打盹
if self.energy <= 0:
self.transition_to("Sleep")
# 5% 概率触发伸懒腰
elif random.random() < 0.05:
self.transition_to("Stretch")
elif self.state == "Sleep":
# 睡 10 次调度后醒来
if self.energy >= 50:
self.transition_to("Idle")
else:
self.energy += 5
elif self.state == "Stretch":
# 伸懒腰一次后恢复闲逛
self.transition_to("Idle")
def transition_to(self, new_state):
"""切换状态并加载相应动画。"""
self.state = new_state
if new_state == "Idle":
self.movie.stop()
self.movie = QMovie("assets/cat_idle.gif")
self.movie.start()
elif new_state == "Sleep":
self.movie.stop()
self.movie = QMovie("assets/cat_sleep.gif")
self.movie.start()
elif new_state == "Stretch":
self.movie.stop()
self.movie = QMovie("assets/cat_stretch.gif")
self.movie.start()
# 每次切换都要调整窗口大小,以适应不同动作帧
self.resize(self.movie.currentPixmap().size())
def random_walk(self):
"""在 Idle 状态下,猫进行随机漫步;其他状态不移动。"""
if self.state != "Idle":
return
# 当前窗口位置
x, y = self.x(), self.y()
# 随机生成一个微小位移
dx = random.randint(-5, 5)
dy = random.randint(-5, 5)
# 限制不超出屏幕范围(假设 1920x1080)
screen_w, screen_h = 1920, 1080
new_x = max(0, min(x + dx, screen_w - self.width()))
new_y = max(0, min(y + dy, screen_h - self.height()))
self.move(new_x, new_y)
代码解析
我在 __init__
中新增了两个定时器:
- state_timer:每 500ms 触发一次,用于消耗“精力”、判断何时进入打盹或伸腰,并完成状态切换。
- move_timer:每 50ms 触发一次,用于在闲逛状态下不断更新位置,形成平滑的移动效果。
update_state
方法根据当前 self.state
执行不同逻辑。为了让猫猫不至于一直打盹不醒,我设计了一个“精力”数值,越睡越充电;当“精力”充满了一半,就重新开始闲逛。
transition_to
方法负责加载并播放对应状态的 GIF 动画,同时根据新动画的画布大小重新调整窗口尺寸,保证不会出现画面裁剪。
random_walk
则是在闲逛状态下,随机生成 -5~5 像素的偏移,并且做屏幕边界检查,避免猫猫跑出桌面可见区域。
到此为止,我们的猫猫已经能自己在桌面上“走动”—走着走着一累就打个盹,偶尔还会伸个懒腰。为了让整个体验更丰富,下面将加入与用户交互的托盘菜单和右键菜单,以及音效反馈。
六、托盘与右键菜单:让猫猫与你互动
一个只会自己晃来晃去的桌面宠物还是略显孤零零,于是我决定:
- 在任务栏托盘(System Tray)里放一个猫爪图标,右键可快速退出或打开设置。
- 点击动画窗口本身弹出一个小菜单,支持“喂食”、“换皮肤”、“查看今日心情”等操作。
系统托盘图标
PyQt5 里使用 QSystemTrayIcon
很方便。先在主程序里初始化托盘:
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QAction
from PyQt5.QtGui import QIcon
class PetApp(QApplication):
def __init__(self, argv):
super().__init__(argv)
# 创建主窗口
self.pet = PetWidget()
self.pet.show()
# --- 系统托盘 ---
self.tray = QSystemTrayIcon(QIcon("assets/tray_icon.png"), self)
self.tray.setToolTip("我的小猫咪")
tray_menu = QMenu()
action_show = QAction("显示/隐藏 猫猫")
action_quit = QAction("退出")
tray_menu.addAction(action_show)
tray_menu.addAction(action_quit)
self.tray.setContextMenu(tray_menu)
self.tray.show()
action_show.triggered.connect(self.toggle_pet)
action_quit.triggered.connect(self.exit_app)
def toggle_pet(self):
if self.pet.isVisible():
self.pet.hide()
else:
self.pet.show()
def exit_app(self):
self.pet.close()
self.quit()
这样,右下角就会出现一个猫爪图标。右键它,就能快速隐藏或退出应用,省去了找窗口的麻烦。
右键弹出菜单
为了更直接的互动,我在 PetWidget
里重写了 contextMenuEvent
:
def contextMenuEvent(self, event):
menu = QMenu(self)
feed = menu.addAction("喂食
本文标签:
做了一只哈基米桌宠
版权声明:本文标题:做了一只哈基米桌宠 内容由网友自发贡献,该文观点仅代表作者本人,
转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1747424401a2696019.html,
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论