Tkinter 中嵌入的 Funcanimation 在 blitting 时未正确停止,window 调整大小后动画显示速率增加

Funcanimation embedded in Tkinter not properly stopping while blitting, Animation display rate increase after window resize

问题: 我在 tkinter GUI 中遇到嵌入式 funcanimation 情节的问题。我无法闯入 funcanimation 对象以告诉它停止。没有正确停止动画的结果是,在我的应用程序关闭后发生调用后,我最终得到了计时器。一个额外的问题是,当我将 tkinter window 扩展到全屏时,动画速度显着加快,但当关闭此速度时,调用后会导致更多剩余。

当前解: 在对这个问题进行了大量研究之后,我目前的解决方案是在 funcanimation 启动中设置 repeat=False,然后有一个生成数据的函数检查布尔值,如果 False return 什么都没有。这个策略使帧的动画变得饥饿,并允许它停止并被 self.ani.event_source.stop() 调用杀死。

皱纹: 当动画速度 运行 变慢时,此解决方案对我来说非常有用。这是皱纹出现的地方;当使用 window 右上角的 windows 最大化按钮调整 window 的大小时,动画 加速!。帧速率从 12fps 到 25fps。只有在使用右上角的 windows 按钮调整大小时才会发生这种情况,如果我拖动框架,它不会发生,这让我认为这是 Windows 的事情。即使在我再次最小化 window 之后,这种增加的帧率仍然存在。因为 blit=True init_func 在调整大小时被调用,所以我可以弄清楚为什么或如何加快速度。是否发生了事件刷新?调整大小在做什么?

目标: 从一开始就从我的 funcanimation 中获得最大显示速率(比如我最大化 window 后的速度),但要确保所有的 aftercall 都被正确取消,这样它们就不会在 gui 关闭后被安排。请参阅下面的代码。谢谢你的帮助。

绘图Class:

class ShowImage(MplMap,Thread):

def __init__(self, master):
    #super().__init__
    Thread.__init__(self)
    self.setDaemon(True)
    self.master = master
    #self.to_live_queue = to_live_queue
    self.mplmap = MplMap
    if self.image is None:
        self.image = self.grabFrame() #grabFrame is inherited from MplMap and returns a list of 2 arrays
    v = np.linspace(0, 16383, num=5, endpoint=True)
    self.ax2 = self.fig2.add_axes([0.075,0.075,0.85,0.85])
    self.ax2.set_anchor('N')
    self.ax2.spines['left'].set_color(self.THEME_COLOR)
    self.ax2.spines['right'].set_color(self.THEME_COLOR)
    self.ax2.spines['top'].set_color(self.THEME_COLOR)
    self.ax2.spines['bottom'].set_color(self.THEME_COLOR)
    self.ax2.tick_params(top=False, bottom=False, left=False, right=False,
            labelleft=False, labelbottom=False)
    self.ax2.set_title('Live Image')
    self.ax2.title.set_color(self.THEME_COLOR)
    self.im = self.ax2.imshow(self.image[0], cmap=self.COLORMAP,vmin=0,vmax=16383)
    divider = make_axes_locatable(self.ax2)
    self.cax = divider.append_axes("right", size="3%", pad=0.05)
    self.cbar = self.fig2.colorbar(self.im,cax=self.cax, orientation='vertical',ticks=v)
    self.cbar.outline.set_edgecolor(self.THEME_COLOR)
    self.cax.tick_params(axis='y',colors=self.THEME_COLOR)
    self.cax.set_yticklabels(['{:.0%}'.format(i/16383) for i in v])
    self.cax.yaxis.label.set_color(self.THEME_COLOR)
    #self.fig2.subplots_adjust(bottom=0.07)
    self.canvas2.draw()
    self.root.update()
    self.running=False
    
def clear_image(self):
    self.im.set_data(np.zeros((128,128)))
    self.root.update_idletasks()
    print('init_func')
    return [self.im]
def run(self):
    self.running=True
    self.ani = FuncAnimation(self.fig2, self.show_image, self.data_gen,blit=True,repeat=False,init_func=self.clear_image, interval=50,cache_frame_data=True)
    return
def data_gen(self):
    while self.running:
        yield self.grabFrame() #grabFrame is inherited from MplMap and returns a list of 2 arrays
    return
def show_image(self,args):
    self.im.set_data(args[0])
    self.root.update_idletasks()
    return [self.im]

def cancel_self(self):
    self.running = False
    time.sleep(0.1)
    self.ani.event_source.stop()
    self.ani._stop()
    self._clear2()
    print('canceled')
    return

启动函数: 这是一个线程 class 这就是为什么我需要 .start() 调用上面的 run 函数的原因。

self.SImg = ShowImage(self.root)
self.SImg.start()

杀函数:

self.SImg.cancel_self()
self.SImg.join()

这两个调用通过 root.wm_protocol('WM_DELETE_WINDOW',test_gui._quit) 链接到框架右上角的 window 关闭按钮,它基本上停止并加入所有其他 运行 线程我的程序。

示例错误: 这是我在关闭程序后启动程序时遇到的错误,同时在最大化后以更高的帧速率显示。

    invalid command name "2102617692744_on_timer"
    while executing
"2102617692744_on_timer"
    ("after" script)

在此处找到此问题的解决方案:

调整大小事件停止并重新启动 event_source,出于某种原因,它以正确的速率将动画设置为 运行。我只是在 show_image() 函数中添加了以下行,并在 init.

中添加了一个整数变量
 if self.i==0:
        self.ani.event_source.stop()
        self.ani.event_source.start()
        self.i+=1

仍然不确定为什么我必须在启动动画时明确地执行此操作以使其以适当的速度到达 运行 但它有效。