python实现的可爱卸载动画

在逛掘金时,掘金用户在B站看到的灵感进行的一个卸载窗口的动画效果的实用案例。人类是一种不断在学习的动物,并且是一种模仿能力学习能里比较强的动物。我这里是第三波的学习实践者咯!

相对VUE构建动画效果窗口,我更加喜欢用python来进行实现可爱卸载动画效果。其实,类似的软件卸载窗口,我们可以在一些常用的软件平台上进行看到,他们做的会更加的精美,同时在操作的过程当中也会流畅和丝滑太多。软件在用户在体验过程中进行最后的一次挽留用户的一次机会。

我们自己做的过程当中更多的是对功能的一个实现以及在实现过程当中的学习拓展,搞定后的满满的成就感。我们始终在孜孜不倦,同时又在乐此不疲。希望能够在不同的维度上为你带来一些灵感。

python 复制代码
import tkinter as tk
from tkinter import ttk

class EmojiDialog:
    def __init__(self, parent):
        self.top = tk.Toplevel(parent)
        self.top.title("表情弹窗")
        self.top.geometry("640x480")
        self.top.configure(bg='#f5f5f7')  # 苹果风格背景颜色
        
        # 初始化状态变量
        self.hue_deg = 49
        self.cheek_alpha = 1.0
        self.eye_scale = 1.0
        self.mouth_radius = [5, 5, 5, 5]
        self.eye_pos = [90, 80, 10, 20]
        self.is_leaving = False

        # 创建画布
        self.canvas = tk.Canvas(self.top, width=600, height=400, bg='#f5f5f7', highlightthickness=0)
        self.canvas.pack(pady=20)

        # 绘制初始元素
        self.draw_emoji()

        # 绑定事件
        self.canvas.bind("<Motion>", self.on_mouse_move)
        self.canvas.bind("<Leave>", self.on_mouse_leave)

        # 自定义按钮样式
        self.style = ttk.Style()
        self.style.theme_use('clam')  # 使用'clam'主题,允许更多样式定制
        self.style.configure('TButton', 
                             background='#eaeaea',
                             foreground='black',
                             font=('Helvetica', 12, 'bold'),
                             padding=10,
                             relief='flat')
        self.style.map('TButton',
                       background=[('active', '#d0d0d0')])
        
        # 按钮容器
        button_frame = ttk.Frame(self.top, style='TFrame')
        button_frame.pack(pady=20)

        ttk.Button(button_frame, text="保留", command=self.some_command).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="卸载", command=self.some_command).pack(side=tk.LEFT, padx=10)

    def draw_emoji(self):
        self.canvas.delete("all")
        self.draw_head()
        self.draw_eyes()
        self.draw_mouth()
        self.draw_cheeks()

    def draw_head(self):
        base_color = self.hsl_to_rgb(self.hue_deg, 100, 65.29)
        color_hex = f"#{base_color[0]:02x}{base_color[1]:02x}{base_color[2]:02x}"
        self.canvas.create_oval(200, 80, 400, 280, outline="#e6d706", width=3, fill=color_hex)

    def draw_eyes(self):
        self.draw_eye(250, 140, self.eye_pos[0], self.eye_pos[1])  # 左眼
        self.draw_eye(350, 140, self.eye_pos[2], self.eye_pos[3])  # 右眼

    def draw_eye(self, x, y, dx, dy):
        self.canvas.create_oval(x - 25, y - 25, x + 25, y + 25, fill="white", outline="")
        scale_factor = 1 + (self.eye_scale - 1) / 3
        eye_size = 22 * scale_factor
        eye_x = x + (dx / 100) * 25 - eye_size / 2
        eye_y = y + (dy / 100) * 25 - eye_size / 2
        self.canvas.create_oval(eye_x, eye_y, eye_x + eye_size, eye_y + eye_size, fill="#5f0303", outline="")

    def draw_mouth(self):
        x, y = 300, 200
        r = self.mouth_radius
        self.canvas.create_rectangle(
            x - 45 + r[0], y - 20 + r[2],
            x + 45 - r[1], y + 30 - r[3],
            fill="#ad2424", outline="#ac0c0c", width=2, activedash=(5, 2)
        )

    def draw_cheeks(self):
        cheek_color = self.rgba_to_hex(250, 147, 147, self.cheek_alpha)
        self.canvas.create_oval(150, 200, 200, 250, fill=cheek_color, outline="")
        self.canvas.create_oval(400, 200, 450, 250, fill=cheek_color, outline="")

    def on_mouse_move(self, event):
        if self.is_leaving:
            return
        x = max(200, min(event.x, 400)) - 200
        y = max(80, min(event.y, 280)) - 80
        width, height = 200, 200

        self.hue_deg = 49 + 91 * (x / width)
        self.cheek_alpha = max(0.1, 1 - (x / (width - 50)))
        self.eye_scale = 1 + (x / width) / 3

        self.eye_pos = [
            (x / width) * 100, (y / height) * 100,
            (x / width) * 100, (y / height) * 100
        ]

        mr = x / width
        self.mouth_radius = [
            max(5, mr * 50), max(5, mr * 50),
            max(5, 50 - mr * 45), max(5, 50 - mr * 45)
        ]

        self.draw_emoji()

    def on_mouse_leave(self, event):
        self.is_leaving = True
        self.reset_state()
        self.draw_emoji()
        self.is_leaving = False

    def reset_state(self):
        self.hue_deg = 49
        self.cheek_alpha = 1.0
        self.eye_scale = 1.0
        self.mouth_radius = [5, 5, 5, 5]
        self.eye_pos = [90, 80, 10, 20]

    def hsl_to_rgb(self, h, s, l):
        h /= 360
        s /= 100
        l /= 100
        if s == 0:
            rgb = (l * 255, l * 255, l * 255)
        else:
            def hue_to_rgb(p, q, t):
                t += 1 if t < 0 else 0
                t -= 1 if t > 1 else 0
                if t < 1 / 6: return p + (q - p) * 6 * t
                if t < 1 / 2: return q
                if t < 2 / 3: return p + (q - p) * (2 / 3 - t) * 6
                return p

            q = l * (1 + s) if l < 0.5 else l + s - l * s
            p = 2 * l - q
            r = hue_to_rgb(p, q, h + 1 / 3)
            g = hue_to_rgb(p, q, h)
            b = hue_to_rgb(p, q, h - 1 / 3)
            rgb = (r * 255, g * 255, b * 255)
        return tuple(int(max(0, min(255, c))) for c in rgb)

    def rgba_to_hex(self, r, g, b, a):
        r = int(r * a + 255 * (1 - a))
        g = int(g * a + 255 * (1 - a))
        b = int(b * a + 255 * (1 - a))
        return f"#{r:02x}{g:02x}{b:02x}"

    def some_command(self):
        print("命令执行")

class MainApp:
    def __init__(self, root):
        self.root = root
        self.root.geometry("300x200")
        self.root.configure(bg='#f5f5f7')  # 设置主窗口背景颜色
        ttk.Button(self.root, text="打开弹窗", command=self.open_dialog).pack(expand=True)

    def open_dialog(self):
        EmojiDialog(self.root)


if __name__ == "__main__":
    root = tk.Tk()
    app = MainApp(root)
    root.mainloop()
相关推荐
尘浮728几秒前
60天python训练计划----day45
开发语言·python
sss191s6 分钟前
校招 java 面试基础题目及解析
java·开发语言·面试
哆啦A梦的口袋呀12 分钟前
基于Python学习《Head First设计模式》第六章 命令模式
python·学习·设计模式
努力搬砖的咸鱼14 分钟前
从零开始搭建 Pytest 测试框架(Python 3.8 + PyCharm 版)
python·pycharm·pytest
Calvex16 分钟前
PyCharm集成Conda环境
python·pycharm·conda
一千柯橘28 分钟前
python 项目搭建(类比 node 来学习)
python
sduwcgg33 分钟前
python的numpy的MKL加速
开发语言·python·numpy
大模型真好玩34 分钟前
可视化神器WandB,大模型训练的必备工具!
人工智能·python·mcp
东方佑36 分钟前
使用 Python 自动化 Word 文档样式复制与内容生成
python·自动化·word
钢铁男儿42 分钟前
Python 接口:从协议到抽象基 类(定义并使用一个抽象基类)
开发语言·python