项目场景:
使用tkinter和pyinstaller 摄像头进行手势识别数字识别等功能封装为一个可执行程序
问题描述
使用tkinter 中Button中转换不同画面功能时 因为使用了tk.after这样的功能,且无法使用tk.after_cancel正常退出循环,会导致两个按键对应的事件同时进行,导致程序卡顿,甚至崩溃。
问题代码:
self.fingerCount_Button = tk.Button(self, text="fingerCount", command=self.fingerCount)
self.fingerCount_Button.pack (side='left')
self.start_Button = tk.Button(self, text="start", command=self.update)
self.fingerCount_Button.pack (side='left')
def fingerCount(self):
# 读取当前帧
ret, frame = self.video.read()
if ret:
# 检测手势
img = self.detector.find_hands(frame, draw=True)
# 中间的代码略了 写的屎山 就不让大家笑话了
cv2.rectangle(img, (200, 0), (300, 100), (0, 255, 0), cv2.FILLED)
cv2.putText(img, str(cnt), (200, 100), cv2.FONT_HERSHEY_DUPLEX, 5, (0, 0, 255))
# 将 OpenCV 图像转换为 PIL 图像
self.image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 在 Canvas 上显示图像
self.canvas.image = ImageTk.PhotoImage(self.image)
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas.image)
self.after(self.delay, self.fingerCount)
def update(self):
# 读取当前帧
ret, frame = self.video.read()
if ret:
# 将 OpenCV 图像转换为 PIL 图像
self.image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
# 在 Canvas 上显示图像
self.canvas.image = ImageTk.PhotoImage(self.image)
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas.image)
self.after(self.delay, self.update)
原因分析:
提示:这里填写问题的分析:我发现虽然点击了另一个按钮 但是没法停止前一个按钮带来的事件 试了普通的tk.after_cancel 无果
解决方案:
提示:这里填写该问题的具体解决方案:要实现同一时间只执行最新点击的按钮对应的事件,可以使用一个变量记录最后一次点击的按钮,并在每次点击按钮时更新这个变量,同时在每个事件执行时判断这个变量是否与当前按钮相同。
import tkinter as tk
class App:
def __init__(self, master):
self.master = master
self.last_btn = None
self.btn1 = tk.Button(self.master, text="Button 1", command=self.on_btn1_click)
self.btn1.pack()
self.btn2 = tk.Button(self.master, text="Button 2", command=self.on_btn2_click)
self.btn2.pack()
def on_btn1_click(self):
self.last_btn = self.btn1
self.do_something()
def on_btn2_click(self):
self.last_btn = self.btn2
self.do_something()
def do_something(self):
if self.last_btn == self.btn1:
print("Button 1 is clicked")
# do something for Button 1
elif self.last_btn == self.btn2:
print("Button 2 is clicked")
# do something for Button 2
else:
print("No button is clicked")
root = tk.Tk()
app = App(root)
root.mainloop()
创建了一个last_btn变量,它用于记录最后一次点击的按钮。在每个按钮的回调函数中,我们更新了last_btn变量,然后调用do_something()方法。在do_something()方法中,我们检查last_btn变量,并根据最后一次点击的按钮执行相应的操作。
这样实现的好处是可以避免同时执行多个事件,保证只有最新点击的按钮对应的事件在执行。