【问题标题】:How to compose widgets correctly in python kivy?如何在 python kivy 中正确组合小部件?
【发布时间】:2021-07-27 14:06:45
【问题描述】:

我想这样做,以便我可以看到循环执行的进度,但是 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()

【问题讨论】:

    标签: python oop kivy widget progress-bar


    【解决方案1】:

    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)
    

    【讨论】:

      【解决方案2】:

      这不是关于组合,而是关于多任务处理,问题是,如果您执行这样的锁定循环,kivy 在循环完成之前无法更新任何内容(因为函数运行时没有其他任何事情发生,没有更新UI 或任何事件的处理)。所以你想要做的是让循环“同时”运行到 kivy 事件循环。

      有多种方法可以做这种事情,它们都或多或少适合不同的情况。

      kivy Clock 允许调度一个函数稍后运行(schedule_once),可能多次运行(schedule_interval),所以你可以有一个更原子的函数,它只是增加进度条的值一次(不是在循环),并使用调度间隔调用此函数。问题是,如果您想在函数中执行实际工作,则可能需要足够长的时间让 UI 在进度条值的增量之间被明显阻塞。

      如果是这种情况,因为您尝试运行的函数很慢,那么您可能希望改为在线程中运行该函数,这样它就不会阻塞 kivy UI。如有必要,您将能够从线程更新进度条的值,使用 Clock 来安排执行此操作的函数(您需要小心不要执行从线程更新 OpenGL 上下文的操作,由于 OpenGL 没有指定这种情况下的行为,所以一些显卡/驱动程序可以很好,但其他人会崩溃你的程序,所以任何从线程更新 UI 都必须使用时钟,有一个 mainthread时钟模块中提供的装饰器)。

      在某些情况下,您可以(因此想要)避免事先做长时间的工作,并找到一种方法来每次需要做最少的工作,然后继续工作,这个想法有一些抽象,比如RecycleView,当你想要显示很长的项目列表时,它可以完全避免创建小部件,只需预先创建数据,并让它根据需要处理小部件的创建/更新.当然,这可能不适用于您的情况,但值得一提的是,以防万一。

      简而言之:不要做这样的循环,或者在线程中做,如果你真的需要这样的循环,请认真考虑,并在使用线程时使用时钟事件来更新你的 UI。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-11
        • 2018-09-23
        相关资源
        最近更新 更多