如何在Tkinter动画运行时让按钮正常响应点击?
问题解决:让Tkinter动画运行时按钮正常响应
核心问题分析
你的代码存在几个关键问题导致按钮无法响应:
- 变量与方法名冲突:按钮的图片对象和点击处理方法同名,导致
command绑定的是图片而非方法 - 手动更新干扰事件循环:
move_canvas里的my_window.update()打乱了Tkinter主循环的事件处理逻辑 - 变量引用错误:未使用
self.访问实例属性,导致方法内无法正确调用类变量 - 类方法定义不规范:
draw_c方法缺少类方法必需的self参数
修正后的完整代码
import tkinter as tk import turtle import random class Application(tk.Frame): def __init__(self, master): super(Application, self).__init__(master) self.switcher = True self.speedx = 5 self.speedy = 5 self.position_x = 0 self.position_y = 0 self.red_clicks_dva = 0 self.green_clicks_dva = 0 self.acuity_list_dva = [60,36,24,18,12,9,6,5,4,3,2.5,2,1.5,1] self.acuity_list_4m_dva = [40,24,16,12,8,6,4,3.33,2.67,2,1.67,1.33,1,0.67] self.characters_dva = ['draw_c','draw_z','draw_o','draw_t','draw_p','draw_f','draw_e','draw_h','draw_v','draw_d','draw_s','draw_n','draw_r'] self.width_value = master.winfo_screenwidth() self.height_value = master.winfo_screenheight() self.launch_dva() def launch_dva(self): for item in self.master.winfo_children(): item.destroy() position = self.green_clicks_dva selected_characters_dva = random.sample(self.characters_dva,1) print(selected_characters_dva) width = self.acuity_list_4m_dva[position]*0.00145*100 self.width_pixel_dva = (width*96)/2.54 self.canvas1 = tk.Canvas(self.master, height=self.width_pixel_dva+10, width=self.width_pixel_dva+10, bg='white', highlightthickness=0) self.canvas1.pack_propagate(False) self.canvas1.place(x=self.position_x, y=self.position_y) self.canvas2 = tk.Canvas(self.master, height=self.width_pixel_dva+10, width=self.width_pixel_dva+10, bg='white', highlightthickness=0) self.canvas2.pack_propagate(False) self.canvas2.place(x=self.position_x, y=self.position_y) turtle_name = turtle.RawTurtle(self.canvas1) turtle_name.speed('fastest') turtle_name.color("black", "white") self.draw_c(turtle_name, self.width_pixel_dva, 0) turtle_name2 = turtle.RawTurtle(self.canvas2) turtle_name2.speed('fastest') turtle_name2.color("black", "white") self.draw_c(turtle_name2, self.width_pixel_dva, 0) # 重命名图片变量,避免与方法名冲突 self.green_btn_img = tk.PhotoImage(file='/home/vevek/Applications/RoundGreen.png') self.yellow_btn_img = tk.PhotoImage(file='/home/vevek/Applications/RoundYellow.png') self.red_btn_img = tk.PhotoImage(file='/home/vevek/Applications/Resized red.png') self.yellow_dva = tk.Button(self.master, image=self.yellow_btn_img, borderwidth=0, bg="white", highlightthickness=0) self.yellow_dva.place(x=self.width_value/2, y=self.height_value-self.height_value/4, anchor="center") # 绑定正确的点击处理方法 self.green_dva = tk.Button(self.master, image=self.green_btn_img, bg="white", command=self.greenbutton_dva, highlightthickness=0, borderwidth=0) self.green_dva.place(x=(self.width_value/2)-100, y=self.height_value-self.height_value/4, anchor="center") self.red_dva = tk.Button(self.master, image=self.red_btn_img, bg="white", command=self.redbutton_dva, highlightthickness=0, borderwidth=0) self.red_dva.place(x=(self.width_value/2)+100, y=self.height_value-self.height_value/4, anchor="center") # 用after调度动画,不手动干扰主循环 self.animate() def move_canvas(self): self.position_x += self.speedx self.position_y += self.speedy target_canvas = self.canvas1 if self.switcher else self.canvas2 target_canvas.place(x=self.position_x, y=self.position_y) # 边界碰撞检测 if self.position_x + self.width_pixel_dva >= self.width_value or self.position_x <= 0: self.speedx *= -1 if self.position_y + self.width_pixel_dva >= (3*self.height_value/4)-100 or self.position_y <= 0: self.speedy *= -1 def animate(self): # 切换canvas显示状态 if self.switcher: self.canvas2.pack_forget() else: self.canvas1.pack_forget() self.move_canvas() self.switcher = not self.switcher # 调度下一次动画帧 self.master.after(10, self.animate) def greenbutton_dva(self): self.green_clicks_dva += 1 self.launch_dva() def redbutton_dva(self): # 正确引用实例变量 print(f"Your dynamic visual acuity is {self.acuity_list_dva[self.green_clicks_dva]}") self.dva_done_flag = 1 self.master.destroy() # 修正类方法定义,添加self参数 def draw_c(self, turtle, width, shade): turtle.penup() turtle.setposition(((width/2)-(width/5)), -((width/4))) turtle.pendown() turtle.shape("blank") turtle.pensize(width/5) turtle.pencolor(shade, shade, shade) turtle.left(50) turtle.circle((width/2 - width/10), -280) turtle.penup() return turtle.turtlesize() if __name__ == "__main__": my_window = tk.Tk() width_value = my_window.winfo_screenwidth() height_value = my_window.winfo_screenheight() my_window.geometry(f"{width_value}x{height_value}+0+0") my_window.configure(bg='white') my_window.title('EYIRIS') app = Application(my_window) my_window.mainloop()
关键修复点
- 重命名图片变量:将
greenbutton_dva这类图片变量改名为green_btn_img,避免与点击处理方法名冲突,确保command绑定正确的方法 - 重构动画逻辑:移除
my_window.update(),改用after方法调度动画帧,让Tkinter主循环能正常处理按钮点击事件 - 修正变量引用:所有类内变量访问添加
self.前缀,确保方法能正确调用实例属性 - 规范类方法定义:给
draw_c方法添加self参数,符合Python类方法的定义规则 - 优化代码封装:用
self.master代替全局的my_window,提升类的封装性
内容的提问来源于stack exchange,提问作者vevek seetharaman
相关产品推荐
相关产品推荐

