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")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值