Python Kivy:正确启动更新 GUI 元素的后台进程

chi*_*ffa 7 python event-handling kivy

我有一个 Python 脚本,它对用户的文件执行一些密集处理,可能需要一些时间。我已经使用 Kivy 为它构建了一个用户界面,它允许用户选择文件、处理模式并在处理过程中向他们显示一些消息。

我的问题是,当主 Kivy 循环传递调用底层用户界面时,窗口会冻结。

据我所知,解决这个问题的正确方法是创建一个单独的进程,脚本将卸载到该进程,并将更新发送到用户界面。

但是,我找不到有关如何执行此操作的示例或有关如何将消息从单独的线程发送回应用程序的任何规范。

有人可以举例说明如何正确执行此操作或将我指向与该主题有关的文档吗?

更新:

为了保持程序的可维护性,我想避免从主线程调用处理器循环的元素,而是调用一个长进程,该进程返回到 GUI 的更新元素,例如进度条或文本字段。看起来这些元素只能从主 kivy 线程中修改。我如何从外部访问它们?

Nyk*_*kin 6

使用此处所述的发布者/消费者模型。以下是该链接中的一个示例,该示例已修改为使用单独的线程:

from kivy.app import App
from kivy.clock import Clock, _default_time as time  # ok, no better way to use the same clock as kivy, hmm
from kivy.lang import Builder
from kivy.factory import Factory
from kivy.uix.button import Button
from kivy.properties import ListProperty

from threading import Thread
from time import sleep

MAX_TIME = 1/60.

kv = '''
BoxLayout:
    ScrollView:
        GridLayout:
            cols: 1
            id: target
            size_hint: 1, None
            height: self.minimum_height

    MyButton:
        text: 'run'

<MyLabel@Label>:
    size_hint_y: None
    height: self.texture_size[1]
'''

class MyButton(Button):
    def on_press(self, *args):
        Thread(target=self.worker).start()

    def worker(self):
        sleep(5) # blocking operation
        App.get_running_app().consommables.append("done")

class PubConApp(App):
    consommables = ListProperty([])

    def build(self):
        Clock.schedule_interval(self.consume, 0)
        return Builder.load_string(kv)

    def consume(self, *args):
        while self.consommables and time() < (Clock.get_time() + MAX_TIME):
            item = self.consommables.pop(0)  # i want the first one
            label = Factory.MyLabel(text=item)
            self.root.ids.target.add_widget(label)

if __name__ == '__main__':
    PubConApp().run()
Run Code Online (Sandbox Code Playgroud)