[英]How to compose widgets correctly in python kivy?
我想这样做,以便我可以看到循环执行的进度,但是 ProgressBar 仅在执行此循环后才退出。 我怎样才能解决这个问题?
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.progressbar import ProgressBar
class MyApp(App):
def build(self):
self.wid = FloatLayout()
self.prog_bar = ProgressBar(max=99999, pos = [0, -150])
self.wid.add_widget(self.prog_bar)
self.prog_bar.value = 0
for i in range(0, 99999):
self.prog_bar.value = i
print(i/99999)
return self.wid
if __name__ == '__main__':
MyApp().run()
Kivy 使用您App
的主线程来更新其小部件。 您正在主线程上运行循环,因此 Kivy 在该循环完成之前无法更新ProgressBar
。 解决方法是在另一个线程中执行循环:
class MyApp(App):
def build(self):
self.wid = FloatLayout()
self.prog_bar = ProgressBar(max=99999, pos=[0, -150])
self.wid.add_widget(self.prog_bar)
self.prog_bar.value = 0
threading.Thread(target=self.do_progress).start()
return self.wid
def do_progress(self):
for i in range(0, 99999):
self.prog_bar.value = i
print(i / 99999)
这不是关于组合,而是关于多任务处理,问题是,如果你做这样的锁定循环,kivy 在循环完成之前不能更新任何东西(因为在函数运行时没有其他事情发生,没有更新 UI或处理任何事件)。 所以你想要做的是让循环“并发”运行到 kivy 事件循环。
有多种方法可以做这种事情,它们或多或少都适合不同的情况。
kivy Clock 允许安排一个函数稍后运行( schedule_once
),可能多次( schedule_interval
),所以你可以有一个更原子的函数,它只增加一次进度条的值(不是在循环中),并调用这个函数使用调度间隔。 问题是,如果您想在函数中进行实际工作,则可能需要足够长的时间才能使 UI 在进度条值的增量之间被明显阻塞。
如果这是您的情况,因为您尝试运行的函数很慢,那么您可能希望改为在线程中运行该函数,这样它就不会阻塞 kivy UI。 如有必要,您将能够从线程更新进度条的值,使用 Clock 来安排执行此操作的函数(您需要小心不要执行从线程更新 OpenGL 上下文的操作,由于 OpenGL 没有指定这种情况下的行为,因此某些图形卡/驱动程序可以使用它,但其他图形卡/驱动程序会导致程序崩溃,因此从线程更新 UI 的任何内容都必须使用时钟,提供了一个mainthread
装饰器在时钟模块中)。
在某些情况下,您可以(因此希望)避免事先进行长时间的工作,并找到一种方法在每次需要时完成最少的工作,然后继续工作,该想法有一些抽象,例如RecycleView
,这避免了完全创建小部件,当您想要显示很长的项目列表时,只需事先创建数据,并让它根据需要处理小部件的创建/更新。 当然,这可能不适用于您的情况,但值得一提,以防万一。
简而言之:不要执行这样的循环,或者在线程中执行它们,如果您确实需要这样的循环,请认真思考,并在使用线程时使用时钟事件来更新您的 UI。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.