Python 桌宠代码
import tkinter # 导入 tkinter GUI 库
import os # 导入 os 库用于文件路径操作
import random # 导入 random 库用于随机选择
from platform import system # 导入系统模块以检测操作系统
from PIL import Image, ImageTk # 导入 Pillow 库用于处理图像透明背景
# 定义一个宠物类
class Pet:
def __init__(self):
self.root = tkinter.Tk() # 创建窗口
self.delay = 200 # 设置动画帧之间的延迟 (单位:毫秒)
self.pixels_from_right = 500 # 宠物初始位置相对于右边的像素
self.pixels_from_bottom = 500 # 宠物初始位置相对于底部的像素
self.move_speed = 3 # 设置宠物移动速度 (单位:像素)
# 初始化动画帧数组
self.animation = dict(
flower=[self.get_transparent_image('gifs/flower.gif', i) for i in range(55)], # 加载闲置动画帧
eat=[self.get_transparent_image('gifs/eat.gif', i) for i in range(39)], # 加载闲置动画帧
scorn=[self.get_transparent_image('gifs/scorn.gif', i) for i in range(23)], # 加载闲置转睡眠动画帧
sleep=[self.get_transparent_image('gifs/sleep.gif', i) for i in range(36)] * 2, # 加载睡眠动画帧并复制三次
listenmusic=[self.get_transparent_image('gifs/listenmusic.gif', i) for i in range(39)], # 加载左走动画帧
play=[self.get_transparent_image('gifs/play.gif', i) for i in range(60)] # 加载右走动画帧
)
# 窗口配置
self.root.overrideredirect(True) # 移除窗口边框
if system() == 'Windows':
self.root.wm_attributes('-transparentcolor', 'white') # 设置 Windows 的透明颜色为白色
else: # 如果是 Mac/Linux
self.root.wm_attributes('-transparent', True) # 设置透明属性
self.root.config(bg='systemTransparent') # 设置背景为系统透明
self.root.attributes('-topmost', True) # 确保窗口位于所有其他窗口之上
self.root.bind("<Button-1>", self.onLeftClick) # 绑定左键点击事件
self.root.bind("<Button-3>", self.showpopumenu) # 绑定右键点击事件
self.root.bind("<Key>", self.onKeyPress) # 绑定键盘按键事件
self.root.bind("<B1-Motion>", self.on_drag) # 绑定拖动事件
self.canvas = tkinter.Canvas(self.root, width=100, height=100, bg="white", highlightthickness=0)
self.canvas.pack(expand=True)
screen_width = self.root.winfo_screenwidth() # 获取屏幕宽度
screen_height = self.root.winfo_screenheight() # 获取屏幕高度
self.min_width = 10 # 设置宠物的最小移动边界
self.max_width = screen_width - 110 # 设置宠物的最大移动边界
# 更改窗口的初始位置
self.curr_width = screen_width - self.pixels_from_right # 当前宽度
self.curr_height = screen_height - self.pixels_from_bottom # 当前高度
self.root.geometry(f"{imgWidth}x{imgHeight}+{self.curr_width}+{self.curr_height}")
self.popumenu = tkinter.Menu(self.root, tearoff=False)
for animation in self.animation.keys():
self.popumenu.add_command(label=animation, command=lambda anim=animation: self.change_animation(anim))
def get_transparent_image(self, gif_path, index):
gif = Image.open(gif_path)
gif.seek(index)
return ImageTk.PhotoImage(gif.convert('RGBA'))
def update(self, i, curr_animation):
# 更新窗口状态
self.root.attributes('-topmost', True) # 确保窗口位于最上层
animation_arr = self.animation[curr_animation] # 获取当前动画帧数组
frame = animation_arr[i] # 获取当前帧
self.canvas.delete("all")
self.canvas.create_image(50, 50, image=frame)
self.canvas.image = frame
# 如果需要移动宠物
if curr_animation in ('play', 'scorn'):
self.move_window(curr_animation)
i += 1 # 指向下一帧
if i == len(animation_arr):
# 达到当前动画的末尾,决定下一步动画
next_animation = self.getNextAnimation(curr_animation)
self.root.after(self.delay, self.update, 0, next_animation) # 等待一段时间后更新动画
else:
self.root.after(self.delay, self.update, i, curr_animation) # 否则继续当前动画
def onLeftClick(self, event):
print("检测到左键点击") # 左键点击事件处理函数
def showpopumenu(self, event):
self.popumenu.post(event.x_root, event.y_root)
def onKeyPress(self, event):
if event.char in ('q', 'Q'):
self.quit() # 按下 'q' 或 'Q' 键退出程序
def on_drag(self, event):
self.curr_width = event.x_root - imgWidth // 2
self.curr_height = event.y_root - imgHeight // 2
self.root.geometry(f"{imgWidth}x{imgHeight}+{self.curr_width}+{self.curr_height}")
def move_window(self, curr_animation):
if curr_animation == 'play':
if self.curr_width > self.min_width:
self.curr_width -= self.move_speed # 向左移动
elif curr_animation == 'scorn':
if self.curr_width < self.max_width:
self.curr_width += self.move_speed # 向右移动
self.root.geometry(f"{imgWidth}x{imgHeight}+{self.curr_width}+{self.curr_height}") # 更新窗口位置
def getNextAnimation(self, curr_animation):
# 获取下一个动画类型
if curr_animation == 'flower':
return random.choice(['listenmusic', 'eat', 'play', 'scorn', 'sleep']) # 随机选择下一动画
elif curr_animation == 'eat':
return random.choice(['listenmusic', 'eat', 'play', 'scorn', 'flower'])
elif curr_animation == 'sleep':
return random.choice(['listenmusic', 'eat', 'play', 'scorn', 'flower']) # 随机选择保持睡眠或转为闲置
elif curr_animation == 'listenmusic':
return random.choice(['sleep', 'eat', 'play', 'scorn', 'flower']) # 转为闲置动画
elif curr_animation == 'play':
return random.choice(['listenmusic', 'eat', 'sleep', 'scorn', 'flower']) # 随机选择下一动画
elif curr_animation == 'scorn':
return random.choice(['listenmusic', 'eat', 'play', 'sleep', 'flower']) # 随机选择下一动画
elif curr_animation == 'eat':
return random.choice(['listenmusic', 'sleep', 'play', 'scorn', 'flower']) # 随机选择下一动画
def change_animation(self, animation):
self.update(0, animation)
def run(self):
self.root.after(self.delay, self.update, 0, 'listenmusic') # 开始时设置为闲置状态
self.root.mainloop() # 启动主事件循环
def quit(self):
self.root.destroy() # 销毁窗口,退出程序
if __name__ == '__main__':
print('初始化你的桌面宠物...')
print('要退出,请右键单击宠物')
imgWidth, imgHeight = 100, 100
pet = Pet() # 创建宠物对象
pet.run() # 运行宠物
下面是获取gif动画帧数:
from PIL import Image
import os
def extract_gif_frames(gif_path, output_folder, picturename):
# 打开 GIF 文件
with Image.open(gif_path) as img:
frames = []
durations = []
total_duration = 0
# 遍历每一帧
for frame in range(img.n_frames):
img.seek(frame) # 定位到当前帧
frames.append(img.copy()) # 复制当前帧
duration = img.info['duration'] / 1000.0 # 获取持续时间(秒)
durations.append(duration)
total_duration += duration # 累加总持续时间
# 保存每帧为图片,使用指定的 picturename
frame_filename = os.path.join(output_folder, f'{picturename}_frame_{frame}.png')
img.save(frame_filename)
return total_duration, frames, durations
# 使用示例
gif_path = r'C:\Users\33947\AppData\Local\Programs\Python\Python39\Scripts\GUI\pet\gifs\brushteeth.gif'
output_folder = r'C:\Users\33947\AppData\Local\Programs\Python\Python39\Scripts\GUI\pet\picture\brushteeth'
picturename = 'my_gif' # 自定义文件名前缀
os.makedirs(output_folder, exist_ok=True) # 创建输出文件夹
total_duration, frames, durations = extract_gif_frames(gif_path, output_folder, picturename)
# 输出总持续时间
print(f"Total duration: {total_duration} seconds")
作者:m0_66960730