当前位置: 首页 > news >正文

python实现的可爱卸载动画

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

相对VUE构建动画效果窗口,我更加喜欢用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()

相关文章:

  • 电路基础:【1】PN结二极管制作电桥点亮LED灯
  • django各种mixin用法
  • NodeJS学习笔记
  • HCIA—IP路由静态
  • 代码随想录算法训练营第22天 | 组合 组合总和 电话号码的字母组合
  • react中NavLink和a标签区别
  • 最新的前端场景面试题
  • wxWidgets GUI 跨平台 入门学习笔记
  • gmm_08.pkl 解析 读取
  • wordpress分类名称调用的几种情况
  • Manus邀请码获取方法 + 使用指南(直接领取pdf)
  • TOB企业发展前期,在获客方面容易碰到哪些问题?
  • MyBatis 配置文件核心
  • c++实现在同一台主机两个程序实现实时通信
  • 阿里推出全新推理模型(因果语言模型),仅1/20参数媲美DeepSeek R1
  • ABB 继电器和晶体管输出端子使用
  • 双指针算法
  • 介绍一个能支持高带宽的EDID编辑软件
  • SpringCloud系列教程(十三):Sentinel流量控制
  • python脚本py文件加密 pyarmor
  • 网站域名改了以后新域名301/南京百度快速排名优化
  • 刚刚做的网站怎么排名/友情链接大全
  • 投资公司的经营范围有哪些/seo模拟点击算法
  • 百度一直不收录网站/精准的搜索引擎优化
  • 天猫商城官方网站/商城推广
  • 西安市建设局网站/广州aso优化公司 有限公司