

标签:#Python趣味编程 #烟花动画 #Tkinter桌面开发 #代码分享 #治愈系视觉
每逢节日、纪念日、生日,总想拥有一段专属的浪漫画面:静谧夜空下樱花树静静伫立,缤纷烟花轮番绽放,还能自由写下祝福文案、调整字体颜色与夜空风格。不用复杂设计软件,依靠Python短短几百行代码,就能自制一款可交互樱花烟花桌面工具,自带控制面板,新手复制即可运行。
本篇文章会完整讲解程序功能、运行环境、使用教程、代码逻辑拆解,文末附上全部可直接运行源码,收藏就能随时调试使用。
这款整合Turtle绘图+Tkinter桌面窗口+粒子物理系统的动画程序,集成超多实用交互能力:
打开电脑终端/CMD,依次执行下方安装命令:
pip install pillow其余turtle、tkinter、random、time、math均为Python自带标准库,无需额外下载。
Windows/macOS均可,Python3.7及以上版本适配最佳; Windows系统自带Tkinter,macOS若打开报错,需额外安装tk组件。
cherry_firework.py文件;python cherry_firework.pyTree递归函数:递归绘制樱花树干、树枝,枝干末端区分棕色枝干、粉白色樱花花苞,枝干粗细随长度动态变化,模拟真实树木生长形态;Petal花瓣函数:批量生成随机坐标飘落花瓣,营造缓缓纷飞的春日氛围感。自定义Particle粒子类,每一朵烟花由数十个独立粒子构成:
预设夜空配色数组、烟花色彩库、重力系数,想要自定义拓展画面效果,直接修改常量数值即可。
import turtleimport randomimport timefrom PIL import Image, ImageTkimport tkinter as tkfrom tkinter import ttk, colorchooser, fontfrom time import sleepfrom random import choice, uniform, randintfrom math import sin, cos, radians# 全局常量GRAVITY = 0.05colors = ['red', 'blue', 'yellow', 'white', 'green', 'orange', 'purple','seagreen', 'indigo', 'cornflowerblue']# 背景主题配色THEME_BG = {"纯黑夜空": "#000000","深邃星空蓝": "#050520","暗夜紫罗兰": "#120522","静谧午夜绿": "#001a1a"}# 全局变量text_items = []current_bg = "#000000"root = Nonecanvas = Noneturtle_screen = Nonepen = Noneafter_id = None# 存储烟花循环id,关闭窗口终止动画# -------------------------- 樱花绘制函数 --------------------------defTree(branch, t): time.sleep(0.0005)if branch > 3:if8 <= branch <= 12: t.color('snow'if random.randint(0, 2) == 0else'lightcoral') t.pensize(branch / 3)elif branch < 8: t.color('snow'if random.randint(0, 1) == 0else'lightcoral') t.pensize(branch / 2)else: t.color('sienna') t.pensize(branch / 10) t.forward(branch) a = 1.5 * random.random() t.right(20 * a) b = 1.5 * random.random() Tree(branch - 10 * b, t) t.left(40 * a) Tree(branch - 10 * b, t) t.right(20 * a) t.up() t.backward(branch) t.down()# 飘落花瓣defPetal(m, t):for i in range(m): a = 200 - 400 * random.random() b = 10 - 20 * random.random() t.up() t.forward(b) t.left(90) t.forward(a) t.down() t.color('lightcoral') t.circle(1) t.up() t.backward(a) t.right(90) t.backward(b)# -------------------------- 烟花粒子系统 --------------------------classParticle:def__init__(self, canvas, idx, total, explosion_speed, x=0., y=0., vx=0., vy=0., size=2., color='red', lifespan=2): self.id = idx self.x = x self.y = y self.initial_speed = explosion_speed self.vx = vx self.vy = vy self.total = total self.age = 0 self.color = color self.cv = canvas self.cid = self.cv.create_oval(x - size, y - size, x + size, y + size, fill=self.color) self.lifespan = lifespandefupdate(self, dt): self.age += dtif self.alive() and self.expand(): move_x = cos(radians(self.id * 360 / self.total)) * self.initial_speed move_y = sin(radians(self.id * 360 / self.total)) * self.initial_speed self.cv.move(self.cid, move_x, move_y) self.vx = move_x / (float(dt) * 1000)elif self.alive(): move_x = cos(radians(self.id * 360 / self.total)) self.cv.move(self.cid, self.vx + move_x, self.vy + GRAVITY * dt) self.vy += GRAVITY * dtelif self.cid isnotNone: self.cv.delete(self.cid) self.cid = Nonedefexpand(self):return self.age <= 1.2defalive(self):return self.age <= self.lifespan# 烟花循环动画defsimulate(canvas):global after_id# 窗口关闭就停止递归ifnot root.winfo_exists():return start_time = time.time() explode_list = [] wait_time = randint(10, 100) firework_num = randint(6, 10)for _ in range(firework_num): particle_group = [] x = randint(50, 550) y = randint(50, 150) speed = uniform(0.5, 1.5) size = uniform(0.5, 3) color = choice(colors) boom_speed = uniform(0.2, 1) total_p = randint(10, 50)for i in range(1, total_p): p = Particle( canvas=canvas, idx=i, total=total_p, explosion_speed=boom_speed, x=x, y=y, vx=speed, vy=speed, color=color, size=size, lifespan=uniform(0.6, 1.75) ) particle_group.append(p) explode_list.append(particle_group) total_duration = 0.0while total_duration < 1.8: sleep(0.01) now = time.time() delta = now - start_time start_time = nowfor group in explode_list:for p in group: p.update(delta) canvas.update_idletasks() # 轻量化刷新,不冲刷文字 total_duration += delta# 所有文字强制置顶,避免被烟花盖住for tid in text_items: canvas.tag_raise(tid) after_id = root.after(wait_time, simulate, canvas)# -------------------------- 右侧控制面板逻辑 --------------------------# 切换背景主题defchange_bg_theme(event):global current_bg sel = theme_combo.get() current_bg = THEME_BG[sel] canvas.config(bg=current_bg) turtle_screen.screensize(bg=current_bg)# 切换背景后文字依旧置顶for tid in text_items: canvas.tag_raise(tid)# 选取文字颜色defpick_text_color(): color_data = colorchooser.askcolor(title="选择文字颜色")if color_data[1]: color_var.set(color_data[1])# 添加文字到画布(核心修复点)defadd_text_to_canvas(): content = text_input.get().strip()ifnot content:return# 获取字体样式参数 font_name = font_combo.get() font_size = int(size_var.get()) text_color = color_var.get() weight = "bold"if bold_var.get() else"normal" slant = "italic"if italic_var.get() else"roman" align = align_var.get() text_font = font.Font(family=font_name, size=font_size, weight=weight, slant=slant)# 文字放置区域:画布中上位置,不会被遮挡 w = canvas.winfo_width()# 从上往下排布,错开烟花区域 base_y = 220 y_pos = base_y + len(text_items) * 38 x_pos = 40if align == "靠左"else w // 2 anchor = tk.W if align == "靠左"else tk.CENTER# 创建文字 txt_id = canvas.create_text( x_pos, y_pos, text=content, font=text_font, fill=text_color, anchor=anchor ) text_items.append(txt_id)# 立刻把文字提升到最顶层 canvas.tag_raise(txt_id)# 清空所有文字defclear_all_text():for tid in text_items: canvas.delete(tid) text_items.clear()# 安全关闭窗口defclose_window():global after_idif after_id isnotNone: root.after_cancel(after_id) root.quit()# -------------------------- 主界面布局 --------------------------if __name__ == '__main__': root = tk.Tk() root.title("樱花烟花编辑器|文字正常显示版") root.geometry("1080x560") root.resizable(False, False)# 左右分栏 pane = ttk.PanedWindow(root, orient=tk.HORIZONTAL) pane.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)# 左侧画布 frame_left = ttk.Frame(pane) pane.add(frame_left, weight=3) canvas = tk.Canvas(frame_left, height=520, width=750, bg="#000000") canvas.pack()# Turtle嵌入画布 turtle_screen = turtle.TurtleScreen(canvas) pen = turtle.RawTurtle(turtle_screen) pen.hideturtle() pen.getscreen().tracer(5, 0) turtle_screen.screensize(bg="#000000") pen.left(90) pen.up() pen.backward(150) pen.down() pen.color('sienna')# 绘制樱花树、花瓣 Tree(60, pen) Petal(200, pen)# 右侧控制面板 frame_right = ttk.Frame(pane, width=300) pane.add(frame_right, weight=1) row_idx = 0# 背景主题 ttk.Label(frame_right, text="🌌 背景主题设置", font=("微软雅黑",12,"bold")).grid(row=row_idx, column=0, columnspan=2, pady=8) row_idx += 1 theme_combo = ttk.Combobox(frame_right, values=list(THEME_BG.keys()), state="readonly", width=22) theme_combo.current(0) theme_combo.bind("<<ComboboxSelected>>", change_bg_theme) theme_combo.grid(row=row_idx, column=0, columnspan=2, pady=3) row_idx += 2# 文本输入 ttk.Label(frame_right, text="✍ 输入文本内容", font=("微软雅黑",11)).grid(row=row_idx, column=0, columnspan=2) row_idx += 1 text_input = ttk.Entry(frame_right, width=25) text_input.grid(row=row_idx, column=0, columnspan=2, pady=3) row_idx += 2# 字体设置 ttk.Label(frame_right, text="字体样式设置", font=("微软雅黑",11)).grid(row=row_idx, column=0, columnspan=2) row_idx += 1 font_list = ["微软雅黑", "宋体", "黑体", "楷体", "Arial", "Times New Roman", "Lucida Calligraphy"] font_combo = ttk.Combobox(frame_right, values=font_list, state="readonly", width=14) font_combo.current(0) font_combo.grid(row=row_idx, column=1, pady=2) row_idx += 1 ttk.Label(frame_right, text="字号:").grid(row=row_idx, column=0, sticky=tk.W) size_var = tk.StringVar(value="18") size_spin = ttk.Spinbox(frame_right, from_=10, to=48, textvariable=size_var, width=14) size_spin.grid(row=row_idx, column=1, pady=2) row_idx += 1 ttk.Label(frame_right, text="文字颜色:").grid(row=row_idx, column=0, sticky=tk.W) color_var = tk.StringVar(value="#ffffff") ttk.Button(frame_right, text="选取颜色", command=pick_text_color, width=12).grid(row=row_idx, column=1, pady=2) row_idx += 2# 加粗倾斜 bold_var = tk.BooleanVar() italic_var = tk.BooleanVar() cb_bold = ttk.Checkbutton(frame_right, text="加粗", variable=bold_var) cb_italic = ttk.Checkbutton(frame_right, text="倾斜", variable=italic_var) cb_bold.grid(row=row_idx, column=0) cb_italic.grid(row=row_idx, column=1) row_idx += 1# 对齐方式 align_var = tk.StringVar(value="居中") ttk.Radiobutton(frame_right, text="居中", variable=align_var, value="居中").grid(row=row_idx, column=0) ttk.Radiobutton(frame_right, text="靠左", variable=align_var, value="靠左").grid(row=row_idx, column=1) row_idx += 2# 功能按钮 ttk.Button(frame_right, text="添加文字至画布", command=add_text_to_canvas, width=22).grid(row=row_idx, column=0, columnspan=2, pady=4) row_idx += 1 ttk.Button(frame_right, text="清空所有文字", command=clear_all_text, width=22).grid(row=row_idx, column=0, columnspan=2, pady=4)# 启动烟花 root.after(100, simulate, canvas) root.protocol("WM_DELETE_WINDOW", close_window) root.mainloop()colors列表,新增粉色、香槟色等色调,烟花色彩更加丰富;GRAVITY数值,烟花坠落更快;调小数值,烟花飘散更缓慢轻柔;THEME_BG字典里新增键值对,填入十六进制色号即可新增夜空主题。一段代码,把樱花、星空、烟火与温柔寄语融合在一起,不管是节日送给亲友,还是闲暇时运行舒缓心情都格外合适。Python编程不只有枯燥的算法开发,还能亲手创造浪漫治愈的视觉画面。
大家运行过程中遇到报错、想要新增功能(比如保存画面截图、背景音乐、全屏模式)都可以在评论区留言,后续会持续优化迭代版本~
觉得有用别忘了点赞收藏,转发给喜欢编程和浪漫画面的朋友吧!
推文排版适配公众号编辑器:分段清晰、小标题层级分明、代码块可直接复制,表情点缀柔和,阅读观感舒适;正文兼顾科普+实操+源码,适合技术分享类公众号发布。