我想向我通过 Tkinter 中的 Canvas 创建的自定义按钮添加一些动画。但是,我无法正确管理事件,而且我的动画经常无法正常工作。
这是一个代码:
from tkinter import *
import threading
import time
import ctypes
ctypes.windll.shcore.SetProcessDpiawareness(1)
class AACloseButton(Frame):
def __init__(self,_x=170,_y=0,fg="black",**kw):
super().__init__(borderwidth=0,height=10,width=10,bg='white',**kw)
self.cnv = Canvas(self,highlightthickness=0,relief="flat",height=32,width=201,bg="white")
self.cnv.pack(side=RIGHT)
d1,d2 = 100,31
self.check1,self.check2 = False,False
# self.left = False
self.cover = self.cnv.create_rectangle(_x,_y,_x + d1,_y + d2,tags=["p098","io9"])
self.text = self.cnv.create_text(_x + (d1 / 2) + 15,_y + (d2 / 2),fill=fg,text="Close",tags=["p097","io9"])
self.rect3 = self.cnv.create_rectangle(_x + 1,_y + 1,_x + d2,tags=["p092","io9"],fill="red",width=0)
self.l1 = self.cnv.create_line(_x + 2,_y + 2,_x + d2 - 2,_y + d2 - 2,fill="white",tags=["io9","p094"])
self.l2 = self.cnv.create_line(_x + d2 - 2,_x + 2,"p093"])
self.cnv.bind("<Leave>",self._aout)
self.cnv.bind("<Enter>",self._ain)
def _ain(self,event):
print("Inserted")
try:
del self.r2
except AttributeError:
pass
def worker():
try:
xchg = self.r3.is_alive()
except AttributeError:
xchg = False
self.check1 = True
if not xchg:
for i in range(30):
self.cnv.move("io9",-2,0)
time.sleep(0.0001)
if self.check2:
self.check2 = False
self.check1 = False
self.cnv.move("io9",(i + 1) * 2,0)
break
self.check1 = False
self.r2 = threading.Thread(target=worker,daemon=True)
self.r2.start()
def _aout(self,event):
print("Left")
try:
del self.r3
except AttributeError:
pass
def worker():
self.check2 = True
if not self.r2.is_alive():
for i in range(30):
self.cnv.move("io9",2,0)
time.sleep(0.0001)
if self.check1:
self.check1 = False
self.check2 = False
self.cnv.move("io9",-(i + 1) * 2,0)
break
self.check2 = False
self.r3 = threading.Thread(target=worker,daemon=True)
self.r3.start()
if __name__ == '__main__':
root = Tk()
root.geometry("200x200")
root.tk.call('tk','scaling',2)
q = AACloseButton()
q.pack(pady=10)
root.mainloop()
这是带有 .after()
的代码,而不是线程:
from tkinter import *
import ctypes
ctypes.windll.shcore.SetProcessDpiawareness(1)
class AACloseButton(Frame):
def __init__(self,31
self.co1,self.co2 = 0,0
self.check1,"p094"],width=2)
self.l2 = self.cnv.create_line(_x + d2 - 2,"p093"],width=2)
self.cnv.bind("<Leave>",event=None):
self.co1 += 1
self.check2 = True
self.cnv.move("io9",0)
if self.check1:
self.check1 = False
self.cnv.move("io9",(self.co1 + 1) * 2,0)
self.co1 = 0
elif self.co1 == 29:
self.check1 = False
self.check2 = False
self.co1 = 0
else:
self.after(10,self._ain)
def _aout(self,event=None):
self.co2 += 1
self.check1 = True
self.cnv.move("io9",0)
if self.check2:
self.check2 = False
self.cnv.move("io9",-(self.co2 + 1) * 2,0)
self.co2 = 0
elif self.co2 == 29:
self.check1 = False
self.check2 = False
self.co2 = 0
else:
self.after(10,self._aout)
if __name__ == '__main__':
root = Tk()
root.geometry("200x200")
root.tk.call('tk',2)
q = AACloseButton()
q.pack(pady=10)
root.mainloop()
目前,该按钮是可用的,但有一些错误:当您尝试在鼠标上按下按钮离开 canvas
时,“离开”事件会触发两次(一次指针离开画布,一次在释放按钮)。此外,有时,当您快速移动鼠标时,按钮可能会弄错位置。
能否请你向我解释一下我做错了什么?
正如@TheLizzard 所建议的那样,我已经用 .after()
重新制作了我的程序。它的效果要好得多; 但是,按下按钮的错误并未修复。