如何让使用Tkinter按钮的Python Turtle程序持续运行?
问题描述
我用Python Turtle开发了一个战争统计计算器,通过Tkinter按钮构建UI,但脱离IDLE打开后程序无法持续运行。尝试在按钮代码后添加循环或time.sleep(),结果程序直接无响应。使用Windows 11系统、Python 3.12.3版本,网上查找的解决方案均无效。
原代码如下:
import time import turtle from turtle import Screen from tkinter import * screen = turtle.Screen() screen.setup(width=1000, height=400) screen.title("WBT war stat calculator") screen.bgcolor("light blue") canvas = screen.getcanvas() save_mil = "" save_diplo = "" save_eco = "" save_land = "" def update_total(): if not save_mil == "": if not save_diplo == "": if not save_eco == "": if not save_land == "": write_total.clear() stat1 = (((((save_eco / 3) * 2) + (save_diplo / 3) + save_mil) / 2) * save_land) write_total.write(stat1, font=("Arial",30)) def make_text(x, y): writer = turtle.Turtle() writer.penup() writer.speed(0) writer.hideturtle() writer.goto(x, y) return writer def make_textbox(title1, des1, title2, des2, limit, type1): answer = screen.textinput(title1, des1) global save_mil global save_diplo global save_eco global save_land if answer == None: pass else: try: stat = float(answer) if stat > limit: pass else: if type1 == 1: save_mil = stat write_mil.clear() write_mil.write(stat, font=("Arial",30)) if type1 == 2: save_diplo = stat write_diplo.clear() write_diplo.write(stat, font=("Arial",30)) if type1 == 3: save_eco = stat write_eco.clear() write_eco.write(stat, font=("Arial",30)) if type1 == 4: save_land = stat write_land.clear() write_land.write(stat, font=("Arial",30)) update_total() except: stat = (limit + 1) while stat > limit: if answer == None: stat = 1 else: try: answer = screen.textinput(title2, des2) stat = float(answer) if stat > limit: pass else: if type1 == 1: save_mil = stat write_mil.clear() write_mil.write(stat, font=("Arial",30)) if type1 == 2: save_diplo = stat write_diplo.clear() write_diplo.write(stat, font=("Arial",30)) if type1 == 3: save_eco = stat write_eco.clear() write_eco.write(stat, font=("Arial",30)) if type1 == 4: save_land = stat write_land.clear() write_land.write(stat, font=("Arial",30)) update_total() except: pass def textbox_mil(): make_textbox(" ", "What are the military stats? 1 - 10", " ", "What are the military stats again? 1 - 10", 10, 1) def textbox_diplo(): make_textbox(" ", "Great, what are the diplomatic stats now? 1 - 10", " ", "Sorry, what are the diplomatic stats now? 1 - 10", 10, 2) def textbox_eco(): make_textbox(" ", "Eco stats? 1 - 10", " ", "Eco stats again? 1 - 10", 10, 3) def textbox_land(): make_textbox(" ", "How much of the earth do you have by percentage? (as decimal)", " ", "Repeat how much of the earth do you have by percentage? (as decimal)", 1, 4) def make_button(x_pos, y_pos, text_t, command_d): button = Button(canvas.master, text = text_t, command = command_d) button.pack() button.place(x = x_pos, y = y_pos) mil_button = make_button(100, 70, "Military", textbox_mil) diplo_button = make_button(100, 140, "Diplomatic", textbox_diplo) eco_button = make_button(100, 210, "Economic", textbox_eco) land_button = make_button(100, 280, "Land%", textbox_land) write_mil = make_text(-300, 100) write_diplo = make_text(-300, 30) write_eco = make_text(-300, -40) write_land = make_text(-300, -110) write_total = make_text(-90, -40) write_extra = make_text(-100, 200) write_extra.pendown() write_extra.goto(-100,-200) write_extra.penup() write_extra.goto(-90,100) write_extra.write("TOTAL:", font=("Arial",30))
解决方案
问题核心是Turtle基于Tkinter运行,必须依赖Tkinter的事件循环才能维持窗口存活和UI交互。手动添加time.sleep()或自定义循环会阻塞事件循环,导致UI无响应;而未手动启动事件循环时,程序会直接退出。
修复步骤
- 移除所有手动添加的
time.sleep()或自定义循环,避免打断Tkinter的事件处理流程。 - 在代码末尾添加Turtle事件循环启动语句:
也可以用screen.mainloop()turtle.done(),两者效果一致,都会启动Tkinter主事件循环,保持窗口运行并响应用户操作。
优化后完整代码(关键修改已标注)
import time import turtle from turtle import Screen from tkinter import * screen = turtle.Screen() screen.setup(width=1000, height=400) screen.title("WBT war stat calculator") screen.bgcolor("light blue") canvas = screen.getcanvas() save_mil = "" save_diplo = "" save_eco = "" save_land = "" def update_total(): if not save_mil == "": if not save_diplo == "": if not save_eco == "": if not save_land == "": write_total.clear() stat1 = (((((save_eco / 3) * 2) + (save_diplo / 3) + save_mil) / 2) * save_land) write_total.write(stat1, font=("Arial",30)) def make_text(x, y): writer = turtle.Turtle() writer.penup() writer.speed(0) writer.hideturtle() writer.goto(x, y) return writer def make_textbox(title1, des1, title2, des2, limit, type1): answer = screen.textinput(title1, des1) global save_mil global save_diplo global save_eco global save_land if answer == None: pass else: try: stat = float(answer) if stat > limit: pass else: if type1 == 1: save_mil = stat write_mil.clear() write_mil.write(stat, font=("Arial",30)) if type1 == 2: save_diplo = stat write_diplo.clear() write_diplo.write(stat, font=("Arial",30)) if type1 == 3: save_eco = stat write_eco.clear() write_eco.write(stat, font=("Arial",30)) if type1 == 4: save_land = stat write_land.clear() write_land.write(stat, font=("Arial",30)) update_total() except: stat = (limit + 1) while stat > limit: if answer == None: stat = 1 else: try: answer = screen.textinput(title2, des2) stat = float(answer) if stat > limit: pass else: if type1 == 1: save_mil = stat write_mil.clear() write_mil.write(stat, font=("Arial",30)) if type1 == 2: save_diplo = stat write_diplo.clear() write_diplo.write(stat, font=("Arial",30)) if type1 == 3: save_eco = stat write_eco.clear() write_eco.write(stat, font=("Arial",30)) if type1 == 4: save_land = stat write_land.clear() write_land.write(stat, font=("Arial",30)) update_total() except: pass def textbox_mil(): make_textbox(" ", "What are the military stats? 1 - 10", " ", "What are the military stats again? 1 - 10", 10, 1) def textbox_diplo(): make_textbox(" ", "Great, what are the diplomatic stats now? 1 - 10", " ", "Sorry, what are the diplomatic stats now? 1 - 10", 10, 2) def textbox_eco(): make_textbox(" ", "Eco stats? 1 - 10", " ", "Eco stats again? 1 - 10", 10, 3) def textbox_land(): make_textbox(" ", "How much of the earth do you have by percentage? (as decimal)", " ", "Repeat how much of the earth do you have by percentage? (as decimal)", 1, 4) def make_button(x_pos, y_pos, text_t, command_d): button = Button(canvas.master, text = text_t, command = command_d) button.pack() button.place(x = x_pos, y = y_pos) mil_button = make_button(100, 70, "Military", textbox_mil) diplo_button = make_button(100, 140, "Diplomatic", textbox_diplo) eco_button = make_button(100, 210, "Economic", textbox_eco) land_button = make_button(100, 280, "Land%", textbox_land) write_mil = make_text(-300, 100) write_diplo = make_text(-300, 30) write_eco = make_text(-300, -40) write_land = make_text(-300, -110) write_total = make_text(-90, -40) write_extra = make_text(-100, 200) write_extra.pendown() write_extra.goto(-100,-200) write_extra.penup() write_extra.goto(-90,100) write_extra.write("TOTAL:", font=("Arial",30)) # 关键:启动Turtle事件循环,维持窗口运行 screen.mainloop()
无效原因说明
time.sleep()会阻塞主线程,Tkinter无法处理按钮点击、窗口刷新等事件,导致程序无响应。- 自定义循环会占用主线程,打断Tkinter的事件处理流程,造成UI冻结。
- IDLE环境下程序能运行是因为IDLE本身会启动Tkinter事件循环,脱离IDLE后必须手动启动。
内容的提问来源于stack exchange,提问作者Charles250211
相关产品推荐
相关产品推荐

