Animation in tkinter



我想给我的自定义按钮添加一些动画,这是我在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, _y + 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, _y + 2, _x + 2, _y + d2 - 2, fill="white", tags=["io9", "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, _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.co1, self.co2 = 0, 0
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, _y + 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"],
width=2)
self.l2 = self.cnv.create_line(_x + d2 - 2, _y + 2, _x + 2, _y + d2 - 2, fill="white", tags=["io9", "p093"],
width=2)
self.cnv.bind("<Leave>", self._aout)
self.cnv.bind("<Enter>", self._ain)
def _ain(self, event=None):
self.co1 += 1
self.check2 = True
self.cnv.move("io9", -2, 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", 2, 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', 'scaling', 2)
q = AACloseButton()
q.pack(pady=10)
root.mainloop()

目前,按钮是可行的,但有一些bug:当你试图离开canvas与按下鼠标按钮"离开"事件触发两次(指针离开画布一次,按钮释放一次)。而且,有时候,当你快速移动鼠标时,按钮可能会搞错它的位置。

你能解释一下我做错了什么吗?

我按照@ theelizzard的建议,用.after()重做了我的程序。它的效果要好得多;但是,按下按钮的错误是不固定的。

尝试使用TkVideo。它使用Tkinter Label小部件播放视频。

它是另一个库,可以使用pip install tkVideo安装。

来自https://pypi.org/project/tkVideo/:

的示例
from tkinter import *
from tkvideo import tkvideo
root = Tk()
my_label = Label(root)
my_label.pack()
player = tkvideo.tkvideo("C:\path\to\video.mp4", my_label, loop = 1, size = (1280,720))
player.play()
root.mainloop()

您可以使用TkVideo制作视频并播放它。

更多信息请访问https://pypi.org/project/tkVideo/。

最新更新