整体效果: 黑色夜空樱花大树、树枝自动生长;自定义古诗存入词库,诗句拆分逐行化作花瓣随风飘散、缓慢下坠;保留夜空烟花动画、右侧控制面板:切换诗词库、飘落速度、文字大小、背景主题、清空诗句;文字永久置顶不会被樱花/烟花遮挡。



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.05WIND_POWER = 0.12# 风力大小,控制诗句横向飘动幅度colors = ['red', 'blue', 'yellow', 'white', 'green', 'orange', 'purple','seagreen', 'indigo', 'cornflowerblue']# 多套经典古诗词库POEM_LIB = {"唐诗精选": ["床前明月光,疑是地上霜","举头望明月,低头思故乡","春眠不觉晓,处处闻啼鸟","夜来风雨声,花落知多少","白日依山尽,黄河入海流","欲穷千里目,更上一层楼" ],"宋词婉约": ["人有悲欢离合,月有阴晴圆缺","但愿人长久,千里共婵娟","昨夜西风凋碧树,独上高楼","衣带渐宽终不悔,为伊消得人憔悴","无可奈何花落去,似曾相识燕归来" ],"山水田园": ["空山新雨后,天气晚来秋","明月松间照,清泉石上流","采菊东篱下,悠然见南山","绿树村边合,青山郭外斜" ]}# 背景配色方案THEME_BG = {"纯黑夜空": "#000000","深邃星空蓝": "#050520","暗夜紫罗兰": "#120522","静谧午夜绿": "#001a1a"}# 全局变量poem_falling_items = [] # 飘落诗词文字对象current_bg = "#000000"root = Nonecanvas = Noneturtle_screen = Nonepen = Noneafter_id = Nonefall_speed = 1.0# 飘落速度倍率current_poem_group = "唐诗精选"# ---------------------- 樱花树干绘制函数 ----------------------defTree(branch, t): time.sleep(0.0004)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)# ---------------------- 飘落诗词文字粒子类(带风力+重力) ----------------------classPoemText:def__init__(self, cv, text_content, size=14): self.cv = cv# 起始位置:樱花树冠区域随机生成 self.x = randint(150, 600) self.y = randint(80, 260) self.text = text_content self.size = size# 下落速度 + 随机横向风力 self.vy = uniform(0.6, 1.3) * fall_speed self.vx = uniform(-WIND_POWER, WIND_POWER)# 字体样式 font_style = font.Font(family="楷体", size=self.size) self.text_id = cv.create_text( self.x, self.y, text=self.text, font=font_style, fill="#ffdddd", anchor=tk.CENTER ) self.life = 0 self.max_life = randint(220, 380) # 文字存活帧数defupdate(self):# 重力下坠 self.y += self.vy# 风力左右飘忽 self.x += self.vx# 微风随机扰动 self.vx += uniform(-0.03, 0.03) self.life += 1# 更新坐标 self.cv.coords(self.text_id, self.x, self.y)# 文字置顶,不被烟花樱花遮挡 self.cv.tag_raise(self.text_id)defis_dead(self):# 落地超时/超出底部销毁return self.y > 510or self.life > self.max_life# ---------------------- 烟花粒子系统 ----------------------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_firework(canvas):global after_idifnot root.winfo_exists():return start_time = time.time() explode_list = [] wait_time = randint(25, 120) firework_num = randint(4, 8)for _ in range(firework_num): particle_group = [] x = randint(50, 550) y = randint(40, 140) speed = uniform(0.4, 1.4) size = uniform(0.4, 2.6) color = choice(colors) boom_speed = uniform(0.2, 0.9) total_p = randint(8, 45)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.5, 1.6) ) particle_group.append(p) explode_list.append(particle_group) total_duration = 0.0while total_duration < 1.6: 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 after_id = root.after(wait_time, simulate_firework, canvas)# ---------------------- 诗词随风飘动主循环 ----------------------defpoem_fall_loop():# 随机新增一句诗词飘落if randint(0, 35) == 0: poem_sentence = choice(POEM_LIB[current_poem_group]) new_text = PoemText(canvas, poem_sentence, size=poem_size_var.get()) poem_falling_items.append(new_text)# 更新所有飘落诗句 del_list = []for idx, item in enumerate(poem_falling_items): item.update()if item.is_dead(): canvas.delete(item.text_id) del_list.append(idx)# 倒序删除,防止索引错乱for idx in reversed(del_list):del poem_falling_items[idx] root.after(35, poem_fall_loop)# ---------------------- 右侧控制面板逻辑 ----------------------# 切换背景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)# 切换诗词库defchange_poem_lib(event):global current_poem_group current_poem_group = poem_lib_combo.get()# 调整飘落速度defset_fall_speed(val):global fall_speed fall_speed = float(val)# 清空所有飘落诗句defclear_all_poem():for item in poem_falling_items: canvas.delete(item.text_id) poem_falling_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("1120x580") root.resizable(False, False)# 左右水平分栏 main_pane = ttk.PanedWindow(root, orient=tk.HORIZONTAL) main_pane.pack(fill=tk.BOTH, expand=True, padx=6, pady=6)# 左侧绘图区 frame_left = ttk.Frame(main_pane) main_pane.add(frame_left, weight=3) canvas = tk.Canvas(frame_left, width=760, height=530, bg="#000000") canvas.pack()# Turtle嵌入画布绘制樱花树 turtle_screen = turtle.TurtleScreen(canvas) pen = turtle.RawTurtle(turtle_screen) pen.hideturtle() pen.getscreen().tracer(6, 0) turtle_screen.screensize(bg="#000000") pen.left(90) pen.up() pen.backward(160) pen.down() pen.color('sienna')# 绘制樱花树与基础花瓣 Tree(62, pen) Petal(220, pen)# 右侧控制面板 frame_right = ttk.Frame(main_pane, width=320) main_pane.add(frame_right, weight=1) row = 0# 标题 ttk.Label(frame_right, text="🌸 古诗樱花树设置", font=("微软雅黑",13,"bold")).grid(row=row, column=0, columnspan=2, pady=10) row += 1# 背景主题 ttk.Label(frame_right, text="背景夜空主题").grid(row=row, column=0, columnspan=2) row += 1 theme_combo = ttk.Combobox(frame_right, values=list(THEME_BG.keys()), state="readonly", width=24) theme_combo.current(0) theme_combo.bind("<<ComboboxSelected>>", change_bg_theme) theme_combo.grid(row=row, column=0, columnspan=2, pady=3) row += 2# 诗词库切换 ttk.Label(frame_right, text="诗词素材库").grid(row=row, column=0, columnspan=2) row += 1 poem_lib_combo = ttk.Combobox(frame_right, values=list(POEM_LIB.keys()), state="readonly", width=24) poem_lib_combo.current(0) poem_lib_combo.bind("<<ComboboxSelected>>", change_poem_lib) poem_lib_combo.grid(row=row, column=0, columnspan=2, pady=3) row += 2# 诗句大小 ttk.Label(frame_right, text="诗词文字大小").grid(row=row, column=0, sticky="w") poem_size_var = tk.IntVar(value=14) size_spin = ttk.Spinbox(frame_right, from_=10, to=26, textvariable=poem_size_var, width=12) size_spin.grid(row=row, column=1) row += 2# 飘落风速滑块 ttk.Label(frame_right, text="随风飘落速度").grid(row=row, column=0, columnspan=2) speed_slider = ttk.Scale(frame_right, from_=0.3, to=2.2, orient=tk.HORIZONTAL, command=set_fall_speed, resolution=0.1, length=220) speed_slider.set(1.0) speed_slider.grid(row=row, column=0, columnspan=2, pady=4) row += 2# 清空诗句按钮 ttk.Button(frame_right, text="清空所有飘落诗词", command=clear_all_poem, width=22).grid(row=row, column=0, columnspan=2, pady=6)# 启动双动画:烟花 + 诗词随风飘落 root.after(120, simulate_firework, canvas) root.after(150, poem_fall_loop) root.protocol("WM_DELETE_WINDOW", close_window) root.mainloop()pip install pillow无需额外图片,直接运行即可
POEM_LIB字典,仿照格式添加诗句:POEM_LIB = {"唐诗精选": [...],"自定义诗词": ["白日放歌须纵酒", "青春作伴好还乡"]}WIND_POWER数值fill="#ffdddd"替换颜色色号randint(0, 35)数字,数字越小诗句生成越密集