Python 实现动态烟花壁纸并显示今日任务事项
介绍使用 Python 结合 tkinter、Pillow 和 pywin32 库开发动态桌面壁纸的方法。核心功能包括绚丽的烟花粒子动画效果、可自定义的今日任务管理列表以及实时日期时间显示。通过状态机控制烟花生命周期,利用 JSON 持久化存储任务数据,并采用分层渲染与频率控制优化性能。程序提供图形化控制面板用于预览和配置,支持 Windows 系统下将动态效果设置为桌面背景。

介绍使用 Python 结合 tkinter、Pillow 和 pywin32 库开发动态桌面壁纸的方法。核心功能包括绚丽的烟花粒子动画效果、可自定义的今日任务管理列表以及实时日期时间显示。通过状态机控制烟花生命周期,利用 JSON 持久化存储任务数据,并采用分层渲染与频率控制优化性能。程序提供图形化控制面板用于预览和配置,支持 Windows 系统下将动态效果设置为桌面背景。

本文介绍如何在 Windows 桌面背景下添加动态效果,优化为显示烟花效果,以及可动态添加今日需要完成的任务事项信息。



将动态烟花效果与任务管理功能相结合,在桌面背景上展示绚丽的烟花动画和任务信息。
- 界面框架:tkinter (GUI 控制面板)
- 系统交互:pywin32 (Windows API 调用)
- 图像处理:Pillow (图像生成与处理)
- 粒子系统:自定义烟花粒子引擎
- 数据持久化:JSON 文件存储
- 动画引擎:基于时间的粒子系统
FireworkWallpaper 类
├── 核心组件
│ ├── FireworkParticle (烟花粒子类)
│ ├── Firework (烟花类)
│ └── TaskItem (任务项类)
├── 初始化模块 (__init__)
├── 用户界面模块 (setup_ui)
├── 任务管理模块
│ ├── load_tasks / save_tasks
│ ├── add_task / delete_task
│ └── update_task_listbox
├── 壁纸控制模块
│ ├── start_firework_wallpaper
│ ├── stop_wallpaper
│ └── start_animation_loop
├── 动画渲染模块
│ ├── animate (主循环)
│ ├── update_fireworks (烟花系统)
│ ├── draw_tasks (任务绘制)
│ └── draw_date_info (日期绘制)
└── 工具函数模块
├── launch_firework
└── start_preview_animation
class FireworkParticle:
"""基础粒子单元,实现物理运动效果"""
def __init__(self, x, y, color, velocity_x, velocity_y, life_time, gravity=0.1):
self.x = x # X 坐标
self.y = y # Y 坐标
self.color = color # 粒子颜色 (RGB)
self.velocity_x = velocity_x # X 轴速度
self.velocity_y = velocity_y # Y 轴速度
self.life_time = life_time # 生命周期
self.age = 0 # 已存活时间
self.gravity = gravity # 重力加速度
self.size = random.uniform(1.5, 3.0) # 随机大小
self.alpha = 255 # 透明度 (0-255)
粒子物理系统实现:
def update(self, delta_time):
"""更新粒子状态 - 模拟物理运动"""
self.age += delta_time
self.velocity_y += self.gravity # 重力影响
self.x += self.velocity_x
self.y += self.velocity_y
# 透明度衰减:生命周期越接近结束越透明
progress = self.age / self.life_time
self.alpha = int(255 * (1 - progress))
return self.age < self.life_time # 返回是否存活
class Firework:
"""完整烟花对象,包含上升、爆炸、消散三个阶段"""
def __init__(self, x, y, color, explosion_height, particle_count=80):
self.state = "rising" # 状态机:rising, exploding, done
self.velocity_y = -random.uniform(8, 12) # 上升速度
self.particles = [] # 爆炸后的粒子集合
self.creation_time = time.time() # 创建时间戳
烟花状态机实现:
def update(self, delta_time):
"""烟花状态机更新"""
if self.state == "rising":
# 上升阶段
self.y += self.velocity_y
if self.y <= self.explosion_height:
self.explode() # 触发爆炸
self.state = "exploding"
elif self.state == "exploding":
# 爆炸阶段
alive_particles = []
for particle in self.particles:
if particle.update(delta_time):
alive_particles.append(particle)
self.particles = alive_particles
# 检查结束条件
if not self.particles and time.time() - self.creation_time > 3:
self.state = "done" # 进入完成状态
return self.state != "done" # 返回是否活跃
def explode(self):
"""烟花爆炸效果 - 生成放射状粒子"""
for _ in range(self.particle_count):
angle = random.uniform(0, 2 * math.pi) # 随机角度
speed = random.uniform(3, 8) # 随机速度
velocity_x = math.cos(angle) * speed # X 方向分量
velocity_y = math.sin(angle) * speed # Y 方向分量
life_time = random.uniform(1.5, 3.0) # 随机生命周期
# 颜色微调,增加视觉效果
color_variation = random.randint(-30, 30)
r = max(0, min(255, self.color[0] + color_variation))
g = max(0, min(255, self.color[1] + color_variation))
b = max(0, min(255, self.color[2] + color_variation))
particle = FireworkParticle(
self.x, self.y, (r, g, b), velocity_x, velocity_y, life_time
)
self.particles.append(particle)
class TaskItem:
"""任务数据模型,支持 JSON 序列化"""
def __init__(self, text, completed=False, created_time=None):
self.text = text
self.completed = completed
self.created_time = created_time or datetime.now()
def to_dict(self):
"""转换为字典,用于 JSON 序列化"""
return {
"text": self.text,
"completed": self.completed,
"created_time": self.created_time.isoformat()
}
@classmethod
def from_dict(cls, data):
"""从字典重建对象,用于 JSON 反序列化"""
return cls(
text=data["text"],
completed=data["completed"],
created_time=datetime.fromisoformat(data["created_time"])
)
class FireworkWallpaper:
def __init__(self):
# 1. 创建主窗口
self.root = tk.Tk()
self.root.title("烟花任务壁纸")
self.root.geometry("800x600")
# 2. 获取屏幕分辨率
self.screen_width = self.root.winfo_screenwidth()
self.screen_height = self.root.winfo_screenheight()
# 3. 烟花系统初始化
self.fireworks = [] # 活跃烟花列表
self.last_firework_time = 0
self.firework_interval = 2.0 # 发射间隔 (秒)
# 4. 颜色预设
self.firework_colors = [
(255, 107, 107), # 红色
(78, 205, 196), # 青色
(255, 234, 167), # 黄色
# ... 更多颜色
]
# 5. 数据持久化设置
self.tasks_file = os.path.join(os.path.dirname(__file__), "tasks.json")
self.load_tasks() # 加载已有任务
def setup_ui(self):
"""创建双栏式布局界面"""
# 深色主题设计
self.root.configure(bg='#1a1a2e') # 深蓝色背景
# 左侧:控制面板
left_frame = tk.Frame(main_frame, bg="#16213e")
left_frame.pack(side="left", fill="both", expand=True)
# 右侧:预览和控制面板
right_frame = tk.Frame(main_frame, bg="#16213e")
right_frame.pack(side="right", fill="both", expand=True)
任务管理系统界面:
# 任务输入系统
self.task_entry = tk.Entry(...)
self.task_entry.bind("<Return>", lambda e: self.add_task()) # 回车键绑定
# 任务列表显示
self.task_listbox = tk.Listbox(...)
self.update_task_listbox() # 更新显示
# 任务操作按钮组
task_buttons_frame = tk.Frame(...)
tk.Button(..., text="标记完成", command=self.mark_task_completed)
tk.Button(..., text="删除", command=self.delete_task)
tk.Button(..., text="清空", command=self.clear_tasks)
def load_tasks(self):
"""从 JSON 文件加载任务数据"""
try:
if os.path.exists(self.tasks_file):
with open(self.tasks_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.tasks = [TaskItem.from_dict(item) for item in data]
except Exception as e:
print(f"加载任务失败:{e}")
self.tasks = []
def save_tasks(self):
"""保存任务数据到 JSON 文件"""
try:
data = [task.to_dict() for task in self.tasks]
with open(self.tasks_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存任务失败:{e}")
def add_task(self):
"""添加新任务"""
text = self.task_entry.get().strip()
if text:
task = TaskItem(text) # 创建任务对象
self.tasks.append(task)
self.task_entry.delete(0, tk.END) # 清空输入框
self.update_task_listbox()
self.save_tasks() # 自动保存
def mark_task_completed(self):
"""切换任务完成状态"""
selection = self.task_listbox.curselection()
if selection:
index = selection[0]
self.tasks[index].completed = not self.tasks[index].completed
self.update_task_listbox()
self.save_tasks()
def start_firework_wallpaper(self):
"""启动壁纸渲染"""
# 1. 防止重复启动
if self.is_running:
return
# 2. 加载背景壁纸
wallpaper_path = r"C:\Users\Administrator\Pictures\bing_wallpapers\bing_wallpaper_20251224_130106.jpg"
self.wallpaper_image = Image.open(wallpaper_path).convert('RGBA')
self.wallpaper_image = self.wallpaper_image.resize(
(self.screen_width, self.screen_height), Image.Resampling.LANCZOS # 高质量缩放
)
# 3. 预加载字体(性能优化)
self.title_font = ImageFont.truetype("msyh.ttc", 80) # 标题字体
self.task_font = ImageFont.truetype("msyh.ttc", 24) # 任务字体
self.date_font = ImageFont.truetype("msyh.ttc", 36) # 日期字体
# 4. 启动动画循环
self.is_running = True
self.root.after(100, self.start_animation_loop)
def animate(self):
"""动画渲染主循环"""
if not self.is_running:
return
try:
current_time = time.time()
delta_time = current_time - self.last_update_time # 帧率控制:约 15FPS
if current_time - self.last_update_time < 0.066:
self.root.after(10, self.animate)
return
self.last_update_time = current_time
self.frame_count += 1
# 创建新图像画布
composite_image = self.wallpaper_image.copy()
draw = ImageDraw.Draw(composite_image)
# 分层渲染
if self.effects['fireworks']:
self.update_fireworks(draw, current_time, delta_time)
if self.effects['tasks_display']:
self.draw_tasks(draw, current_time)
if self.effects['date_display']:
self.draw_date_info(draw, current_time)
# 性能优化:选择性更新壁纸
update_wallpaper = False
if not hasattr(self, 'last_wallpaper_time'):
update_wallpaper = True
elif current_time - .last_wallpaper_time > :
update_wallpaper =
.frame_count % == :
update_wallpaper =
update_wallpaper:
temp_wallpaper_path = os.path.join(os.path.dirname(__file__), )
composite_image.convert().save(temp_wallpaper_path, )
ctypes.windll.user32.SystemParametersInfoW(, , temp_wallpaper_path, )
.last_wallpaper_time = current_time
:
.root.after(, .animate)
def launch_firework(self):
"""发射新烟花"""
# 随机发射位置
x = random.randint(100, self.screen_width - 100)
y = self.screen_height + 50 # 从屏幕底部开始
# 随机参数
color = random.choice(self.firework_colors)
explosion_height = random.randint(100, self.screen_height // 2)
# 创建烟花对象
firework = Firework(x, y, color, explosion_height)
self.fireworks.append(firework)
def update_fireworks(self, draw, current_time, delta_time):
"""更新所有烟花状态"""
# 发射新烟花(概率控制)
if current_time - self.last_firework_time > self.firework_interval:
if random.random() < 0.7: # 70% 概率发射
self.launch_firework()
self.last_firework_time = current_time
# 更新现有烟花
alive_fireworks = []
for firework in self.fireworks:
if firework.update(delta_time): # 更新状态
alive_fireworks.append(firework)
firework.draw(draw) # 绘制烟花
self.fireworks = alive_fireworks
def draw_tasks(self, draw, current_time):
"""在壁纸上渲染任务列表"""
if not self.tasks:
return
# 定位到右上角
start_x = self.screen_width - 400
start_y = 150
# 绘制标题
draw.text((start_x, start_y), "今日任务", fill=(233, 69, 96, 255), font=self.title_font)
# 绘制每个任务
for i, task in enumerate(self.tasks):
y_pos = start_y + 100 + i * 40
# 状态图标和颜色
status_icon = "✓" if task.completed else "○"
status_color = (149, 165, 166, 255) if task.completed else (233, 69, 96, 255)
draw.text((start_x, y_pos), status_icon, fill=status_color, font=self.task_font)
# 任务文本(已完成变灰色)
text_color = (149, 165, 166, 255) if task.completed else (255, 255, 255, )
draw.text((start_x + , y_pos), task.text, fill=text_color, font=.task_font)
def draw_date_info(self, draw, current_time):
"""渲染日期和时间信息"""
now = datetime.now()
# 左上角:日期和星期
draw.text((50, 100), now.strftime("%Y年%m月%d日"), fill=(233, 69, 96, 255), font=self.date_font)
draw.text((50, 150), now.strftime("星期%w").replace("星期 0", "星期日"), fill=(255, 255, 255, 255), font=self.date_font)
# 右下角:实时时间
time_text = now.strftime("%H:%M:%S")
# 计算文字尺寸进行精确定位
bbox = draw.textbbox((0, 0), time_text, font=self.date_font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
time_x = self.screen_width - text_width - 50 # 距离右边 50 像素
time_y = self.screen_height - text_height - 50 # 距离底部 50 像素
draw.text((time_x, time_y), time_text, fill=(78, 205, 196, 255), font=self.date_font)
# 通过发射间隔和概率控制烟花密度
self.firework_interval = 2.0 # 每 2 秒考虑发射一次
if random.random() < 0.7: # 70% 发射概率
self.launch_firework()
# 降低壁纸文件写入频率,避免系统负载过高
update_wallpaper = False
if current_time - self.last_wallpaper_time > 0.3: # 至少间隔 0.3 秒
update_wallpaper = True
elif self.frame_count % 3 == 0: # 每 3 帧强制更新一次
update_wallpaper = True
# 预加载字体,避免每次渲染重新加载
try:
self.title_font = ImageFont.truetype("msyh.ttc", 80)
self.task_font = ImageFont.truetype("msyh.ttc", 24)
self.date_font = ImageFont.truetype("msyh.ttc", 36)
except:
# 备用方案
self.title_font = ImageFont.load_default()
def start_preview_animation(self):
"""在控制面板中显示动画预览"""
def animate():
self.preview_canvas.delete("all")
# 绘制示例烟花效果
self.preview_canvas.create_oval(140, 150, 160, 170, fill="#e94560")
# 绘制爆炸粒子
for i in range(8):
angle = i * math.pi / 4
x = 150 + 30 * math.cos(angle)
y = 100 + 30 * math.sin(angle)
self.preview_canvas.create_oval(x-3, y-3, x+3, y+3, fill="#ffd700")
self.root.after(2000, animate) # 2 秒循环
animate()
# 回车键快速添加任务
self.task_entry.bind("<Return>", lambda e: self.add_task())
# 每次任务操作后自动保存
def add_task(self):
# ... 添加任务逻辑
self.save_tasks() # 自动保存到文件
def mark_task_completed(self):
# ... 标记完成逻辑
self.save_tasks() # 自动保存到文件
启动前,请先安装相关库,创建 requirements.txt 文件:
pywin32>=305 Pillow>=10.0.0
安装依赖:
pip install -r requirements.txt
完整 Python 代码:
import tkinter as tk
from tkinter import messagebox, simpledialog, font
import win32api
import win32con
import win32gui
import sys
import os
import time
import math
import json
from datetime import datetime, timedelta
from threading import Thread
from PIL import Image, ImageDraw, ImageFont, ImageTk
import ctypes
import random
class FireworkParticle:
"""烟花粒子类"""
def __init__(self, x, y, color, velocity_x, velocity_y, life_time, gravity=0.1):
self.x = x
self.y = y
self.color = color
self.velocity_x = velocity_x
self.velocity_y = velocity_y
self.life_time = life_time
self.age = 0
self.gravity = gravity
self.size = random.uniform(1.5, 3.0)
self.alpha = 255
def update(self, delta_time):
"""更新粒子状态"""
self.age += delta_time
self.velocity_y += self.gravity
.x += .velocity_x
.y += .velocity_y
progress = .age / .life_time
.alpha = ( * ( - progress))
.age < .life_time
():
.alpha > :
r, g, b = .color
draw.ellipse([.x - .size, .y - .size, .x + .size, .y + .size], fill=(r, g, b, .alpha))
:
():
.x = x
.y = y
.color = color
.explosion_height = explosion_height
.particle_count = particle_count
.state =
.velocity_y = -random.uniform(, )
.particles = []
.creation_time = time.time()
():
.state == :
.y += .velocity_y
.y <= .explosion_height:
.explode()
.state =
.state == :
alive_particles = []
particle .particles:
particle.update(delta_time):
alive_particles.append(particle)
.particles = alive_particles
.particles time.time() - .creation_time > :
.state =
.state !=
():
_ (.particle_count):
angle = random.uniform(, * math.pi)
speed = random.uniform(, )
velocity_x = math.cos(angle) * speed
velocity_y = math.sin(angle) * speed
life_time = random.uniform(, )
color_variation = random.randint(-, )
r = (, (, .color[] + color_variation))
g = (, (, .color[] + color_variation))
b = (, (, .color[] + color_variation))
particle = FireworkParticle(.x, .y, (r, g, b), velocity_x, velocity_y, life_time)
.particles.append(particle)
():
.state == :
trail_length =
i (trail_length):
alpha = ( * ( - i / trail_length))
size = (, - i * )
draw.ellipse([.x - size, .y + i * - size, .x + size, .y + i * + size], fill=(*.color, alpha))
.state == :
particle .particles:
particle.draw(draw)
:
():
.text = text
.completed = completed
.created_time = created_time datetime.now()
():
{: .text, : .completed, : .created_time.isoformat()}
():
cls(text=data[], completed=data[], created_time=datetime.fromisoformat(data[]))
:
():
.root = tk.Tk()
.root.title()
.root.geometry()
.screen_width = .root.winfo_screenwidth()
.screen_height = .root.winfo_screenheight()
.wallpaper_hwnd =
.is_running =
.fireworks = []
.last_firework_time =
.firework_interval =
.tasks = []
.tasks_file = os.path.join(os.path.dirname(__file__), )
.load_tasks()
.effects = {: , : , : , : }
.firework_colors = [
(, , ),
(, , ),
(, , ),
(, , ),
(, , ),
(, , ),
(, , ),
]
.setup_ui()
():
.root.configure(bg=)
title = tk.Label(.root, text=, font=(, , ), fg=, bg=)
title.pack(pady=)
main_frame = tk.Frame(.root, bg=)
main_frame.pack(fill=, expand=, padx=, pady=)
left_frame = tk.Frame(main_frame, bg=)
left_frame.pack(side=, fill=, expand=, padx=(, ))
effects_frame = tk.LabelFrame(left_frame, text=, font=(, , ), fg=, bg=, padx=, pady=)
effects_frame.pack(fill=, pady=)
.effect_vars = {}
effect, enabled .effects.items():
var = tk.BooleanVar(value=enabled)
.effect_vars[effect] = var
effect_name = {: , : , : , : }[effect]
cb = tk.Checkbutton(effects_frame, text=effect_name, variable=var, font=(, ), fg=, bg=, selectcolor=, activebackground=, activeforeground=)
cb.pack(anchor=, pady=)
tasks_frame = tk.LabelFrame(left_frame, text=, font=(, , ), fg=, bg=, padx=, pady=)
tasks_frame.pack(fill=, expand=, pady=)
task_input_frame = tk.Frame(tasks_frame, bg=)
task_input_frame.pack(fill=, pady=)
.task_entry = tk.Entry(task_input_frame, font=(, ), bg=, fg=, insertbackground=)
.task_entry.pack(side=, fill=, expand=, padx=(, ))
.task_entry.bind(, e: .add_task())
tk.Button(task_input_frame, text=, command=.add_task, font=(, ), bg=, fg=, relief=).pack(side=)
.task_listbox = tk.Listbox(tasks_frame, font=(, ), bg=, fg=, selectbackground=, selectforeground=, height=)
.task_listbox.pack(fill=, expand=, pady=)
.update_task_listbox()
task_buttons_frame = tk.Frame(tasks_frame, bg=)
task_buttons_frame.pack(fill=)
tk.Button(task_buttons_frame, text=, command=.mark_task_completed, font=(, ), bg=, fg=, relief=).pack(side=, padx=)
tk.Button(task_buttons_frame, text=, command=.delete_task, font=(, ), bg=, fg=, relief=).pack(side=, padx=)
tk.Button(task_buttons_frame, text=, command=.clear_tasks, font=(, ), bg=, fg=, relief=).pack(side=, padx=)
right_frame = tk.Frame(main_frame, bg=)
right_frame.pack(side=, fill=, expand=, padx=(, ))
preview_frame = tk.LabelFrame(right_frame, text=, font=(, , ), fg=, bg=, padx=, pady=)
preview_frame.pack(fill=, expand=, pady=)
.preview_canvas = tk.Canvas(preview_frame, width=, height=, bg=, highlightthickness=)
.preview_canvas.pack(fill=, expand=)
control_frame = tk.Frame(right_frame, bg=)
control_frame.pack(fill=, pady=)
tk.Button(control_frame, text=, command=.start_firework_wallpaper, font=(, , ), bg=, fg=, padx=, pady=, relief=, cursor=).pack(fill=, pady=)
tk.Button(control_frame, text=, command=.stop_wallpaper, font=(, ), bg=, fg=, padx=, pady=, relief=, cursor=).pack(fill=, pady=)
.status_label = tk.Label(control_frame, text=, font=(, ), fg=, bg=)
.status_label.pack(pady=)
info_text =
info = tk.Label(control_frame, text=info_text, font=(, ), fg=, bg=, justify=)
info.pack(pady=)
.root.protocol(, .on_closing)
.start_preview_animation()
():
():
.preview_canvas.delete()
.preview_canvas.create_rectangle(, , , , fill=, outline=)
current_time = time.time()
.preview_canvas.create_oval(, , , , fill=, outline=)
i ():
angle = i * math.pi /
x = + * math.cos(angle)
y = + * math.sin(angle)
.preview_canvas.create_oval(x-, y-, x+, y+, fill=, outline=)
.preview_canvas.create_text(, , text=, fill=, font=(, ))
.root.after(, animate)
animate()
():
:
os.path.exists(.tasks_file):
(.tasks_file, , encoding=) f:
data = json.load(f)
.tasks = [TaskItem.from_dict(item) item data]
Exception e:
()
.tasks = []
():
:
data = [task.to_dict() task .tasks]
(.tasks_file, , encoding=) f:
json.dump(data, f, ensure_ascii=, indent=)
Exception e:
()
():
text = .task_entry.get().strip()
text:
task = TaskItem(text)
.tasks.append(task)
.task_entry.delete(, tk.END)
.update_task_listbox()
.save_tasks()
():
selection = .task_listbox.curselection()
selection:
index = selection[]
.tasks[index].completed = .tasks[index].completed
.update_task_listbox()
.save_tasks()
():
selection = .task_listbox.curselection()
selection:
index = selection[]
.tasks.pop(index)
.update_task_listbox()
.save_tasks()
():
messagebox.askyesno(, ):
.tasks = []
.update_task_listbox()
.save_tasks()
():
.task_listbox.delete(, tk.END)
task .tasks:
status = task.completed
display_text =
.task_listbox.insert(tk.END, display_text)
task.completed:
.task_listbox.itemconfig(tk.END, {: })
():
.is_running:
.status_label.config(text=, fg=)
effect, var .effect_vars.items():
.effects[effect] = var.get()
.status_label.config(text=, fg=)
.root.update()
wallpaper_path =
:
.wallpaper_image = Image.(wallpaper_path).convert()
.wallpaper_image = .wallpaper_image.resize((.screen_width, .screen_height), Image.Resampling.LANCZOS)
Exception e:
.status_label.config(text=, fg=)
:
.title_font = ImageFont.truetype(, )
.task_font = ImageFont.truetype(, )
.date_font = ImageFont.truetype(, )
:
.title_font = ImageFont.load_default()
.task_font = ImageFont.load_default()
.date_font = ImageFont.load_default()
.animation_start_time = time.time()
.last_update_time =
.frame_count =
.fireworks = []
.last_firework_time =
.is_running =
.root.after(, .start_animation_loop)
.status_label.config(text=, fg=)
():
.is_running:
.animate()
():
.is_running (, ):
:
current_time = time.time()
delta_time = current_time - .last_update_time (, )
(, ) current_time - .last_update_time < :
.root.after(, .animate)
.last_update_time = current_time
.frame_count +=
composite_image = .wallpaper_image.copy()
draw = ImageDraw.Draw(composite_image)
.effects[]:
.update_fireworks(draw, current_time, delta_time)
.effects[]:
.draw_tasks(draw, current_time)
.effects[]:
.draw_date_info(draw, current_time)
temp_wallpaper_path = os.path.join(os.path.dirname(__file__), )
update_wallpaper =
(, ):
update_wallpaper =
current_time - .last_wallpaper_time > :
update_wallpaper =
.frame_count % == :
update_wallpaper =
update_wallpaper:
composite_image.convert().save(temp_wallpaper_path, )
ctypes.windll.user32.SystemParametersInfoW(, , temp_wallpaper_path, )
.last_wallpaper_time = current_time
Exception e:
()
.root.after(, .animate)
():
current_time - .last_firework_time > .firework_interval:
random.random() < :
.launch_firework()
.last_firework_time = current_time
alive_fireworks = []
firework .fireworks:
firework.update(delta_time):
alive_fireworks.append(firework)
firework.draw(draw)
.fireworks = alive_fireworks
():
x = random.randint(, .screen_width - )
y = .screen_height +
color = random.choice(.firework_colors)
explosion_height = random.randint(, .screen_height // )
firework = Firework(x, y, color, explosion_height)
.fireworks.append(firework)
():
.tasks:
start_x = .screen_width -
start_y =
title_text =
draw.text((start_x, start_y), title_text, fill=(, , , ), font=.title_font)
i, task (.tasks):
y_pos = start_y + + i *
status_icon = task.completed
status_color = (, , , ) task.completed (, , , )
draw.text((start_x, y_pos), status_icon, fill=status_color, font=.task_font)
text_color = (, , , ) task.completed (, , , )
draw.text((start_x + , y_pos), task.text, fill=text_color, font=.task_font)
():
now = datetime.now()
date_text = now.strftime()
week_text = now.strftime().replace(, )
time_text = now.strftime()
date_bbox = draw.textbbox((, ), date_text, font=.date_font)
week_bbox = draw.textbbox((, ), week_text, font=.date_font)
time_bbox = draw.textbbox((, ), time_text, font=.date_font)
date_width = date_bbox[] - date_bbox[]
date_height = date_bbox[] - date_bbox[]
week_width = week_bbox[] - week_bbox[]
week_height = week_bbox[] - week_bbox[]
time_width = time_bbox[] - time_bbox[]
time_height = time_bbox[] - time_bbox[]
base_x = .screen_width - (date_width, week_width, time_width) -
time_y = .screen_height - time_height -
week_y = time_y - week_height -
date_y = week_y - date_height -
draw.text((base_x, date_y), date_text, fill=(, , , ), font=.date_font)
draw.text((base_x, week_y), week_text, fill=(, , , ), font=.date_font)
draw.text((base_x, time_y), time_text, fill=(, , , ), font=.date_font)
():
.is_running =
:
temp_wallpaper_path = os.path.join(os.path.dirname(__file__), )
os.path.exists(temp_wallpaper_path):
os.remove(temp_wallpaper_path)
:
(, ):
(, )
.status_label.config(text=, fg=)
():
.stop_wallpaper()
.save_tasks()
.root.quit()
.root.destroy()
():
:
ctypes.windll.shell32.IsUserAnAdmin():
ctypes.windll.shell32.ShellExecuteW(, , sys.executable, .join(sys.argv), , )
sys.exit()
app = FireworkWallpaper()
app.root.mainloop()
Exception e:
messagebox.showerror(, )
__name__ == :
main()

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online