Kivy执行耗时函数时Popup内GIF动画无法正常播放如何解决
问题根因
Kivy的UI渲染、事件响应全部运行在主线程的事件循环中:
- 使用
Clock.schedule_once提交的任务依然在主线程执行,耗时函数运行时会完全阻塞事件循环,GIF的帧更新逻辑无法得到调度,所以表现为静止状态 - 之前使用多线程失效,是因为要么在子线程直接操作UI(触发线程安全问题),要么耗时函数执行速度快于弹窗渲染速度,才会出现弹窗一闪而过的问题
修正方案
将耗时逻辑完全放到子线程执行,所有UI操作(打开/关闭弹窗、更新进度等)都放回主线程执行,修正后的代码如下:
Python代码
from kivy.app import App from kivy.uix.popup import Popup from kivy.uix.gridlayout import GridLayout from kivy.clock import Clock from kivy.metrics import dp import time, threading class RunningPopup(GridLayout): fpop = None def set_pop(self, pwin): self.fpop = pwin def close(self): self.fpop.dismiss() class ExampleApp(App): def show_popup(self): content = RunningPopup() # 注意:需要把布局封装进Popup组件才能调用open方法 self.pop_up = Popup( title="", content=content, size_hint=(0.8, 0.5), auto_dismiss=False ) content.set_pop(self.pop_up) self.pop_up.open() def process_button_click(self): # 主线程打开弹窗,渲染逻辑正常执行 self.show_popup() # 耗时逻辑放子线程执行,不阻塞主线程 mythread = threading.Thread(target=self.really_long_function) # 设为守护线程,避免APP退出时线程残留 mythread.daemon = True mythread.start() def really_long_function(self): # 模拟耗时操作 thistime = time.time() while thistime + 5 > time.time(): time.sleep(1) # 关闭弹窗属于UI操作,必须抛回主线程执行 Clock.schedule_once(lambda _: self.pop_up.dismiss()) if __name__ == "__main__": ExampleApp().run()
KV代码无需修改,保持你原有写法即可。
注意事项
- 所有UI组件的属性修改、方法调用,都不允许在子线程直接执行,必须通过
Clock.schedule_once提交到主线程调度 - 如果耗时过程中需要更新弹窗内的进度提示、动画状态,也遵循上述规则,将UI操作抛回主线程执行
内容的提问来源于stack exchange,提问作者mdoc-2011
相关产品推荐
相关产品推荐

