为什么我的Kivy加载屏动画不动?程序出现卡顿/冻结问题?
核心问题
你遇到的应用冻结、动画卡住的问题有三个核心原因:
- 线程创建语法错误:
Thread(target=self.spin_widget())这种写法会立刻在主线程执行函数,再把返回值传给target参数,完全没有实现多线程效果。正确用法是给target传函数对象,参数通过args元组传递。 - 耗时任务直接阻塞主线程:你在按钮
on_release回调中直接调用strip_first_brief,函数内的休眠(实际场景为网络请求)会直接阻塞Kivy的UI渲染主线程,导致所有动画、交互停止。 - 你不需要给UI动画开子线程:Kivy的Animation本身就是异步非阻塞的,直接在主线程调用即可生效。
修复方案
1. 修改main.py
补充导入Clock,调整线程逻辑,把所有耗时任务封装到单独函数丢到子线程执行,任务完成后通过Clock调度切屏(UI操作必须在主线程执行):
from kivy.app import App from kivy.lang import Builder from kivy.uix.screenmanager import Screen, NoTransition, CardTransition from kivy.uix.button import ButtonBehavior from kivy.uix.image import Image from kivy.animation import Animation from kivy.clock import Clock import time from threading import Thread class ImageButton(ButtonBehavior, Image): pass class HomeScreen(Screen): pass class Results1Screen(Screen): pass class LoadScreen(Screen): pass GUI = Builder.load_file("main.kv") class TestApp(App): def build(self): return GUI def change_screen(self, screen_name): screen_manager = self.root.ids['screen_manager'] screen_manager.current = screen_name def spin_widget(self): widget = self.root.ids["load_screen"].ids["spinning_widget"] anim = Animation(angle=-3000, duration=40) anim.start(widget) def immediate_screen1(self): self.root.ids["screen_manager"].transition = NoTransition() self.change_screen("load_screen") self.root.ids["screen_manager"].transition = CardTransition() def get_briefing(self, dest1, dest2): # 实际场景替换为你的POST/GET请求逻辑 time.sleep(5) def strip_first_brief(self, destX, etaX): # 实际场景替换为你的处理逻辑 time.sleep(5) def process_all_tasks(self, dest1, eta1): # 所有耗时任务均在子线程执行 self.get_briefing(dest1, "") # 你原代码中未定义manual_dest2,此处替换为实际参数即可 self.strip_first_brief(dest1, eta1) # 任务完成后调度到主线程切屏 Clock.schedule_once(lambda dt: self.change_screen("results_1_screen")) TestApp().run()
2. 修改homescreen.kv的按钮回调逻辑
删除主线程中的耗时任务调用,把所有耗时任务丢到子线程执行:
<HomeScreen>: FloatLayout: canvas: Color: rgb: utils.get_color_from_hex("#000523") Rectangle: size: self.size pos: self.pos TextInput: id: manual_dest1 hint_text: "first destination" text: self.text.upper() if self.text is not None else '' size_hint: .7, .08 pos_hint: {"top": .75, "center_x": .5} TextInput: id: eta1 hint_text: "first ETA in UTC" text: self.text.upper() if self.text is not None else '' size_hint: .7, .08 pos_hint: {"top": .5, "center_x": .5} Button: text: "Strip TAF" pos_hint: {"top": .15, "center_x": .5} size_hint: .5, .08 padding: 20, 20 opacity: 1 if self.state == 'normal' else .5 on_press: app.immediate_screen1() app.spin_widget() on_release: # 耗时任务丢入子线程执行 Thread(target=app.process_all_tasks, args=(manual_dest1.text, eta1.text)).start()
修改后加载动画会全程流畅运行,不会出现卡顿,等10秒(两个sleep的总时长)后会自动切换到结果页。
内容的提问来源于stack exchange,提问作者PW1990
相关产品推荐
相关产品推荐

