You need to enable JavaScript to run this app. Kivy执行耗时函数时Popup内GIF动画无法正常播放如何解决
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 19:06:06