我有一个 Python 脚本,可以对用户文件执行一些密集处理,这可能需要一些时间。我使用 Kivy 为它构建了一个用户界面,允许用户选择文件、处理模式并在过程进行时向他们显示一些消息。
我的问题是,当主 Kivy 循环调用底层用户界面时,窗口卡住。
据我所知,解决此问题的正确方法是创建一个单独的进程,脚本将卸载到该进程,并将更新从该进程发送到用户界面。
但是,我找不到如何执行此操作的示例或有关如何将消息从单独的线程发送回应用程序的任何规范。
有人可以举例说明如何正确地执行此操作或向我指出与该主题相关的文档吗?
更新:
为了保持程序的可维护性,我想避免从主线程调用处理器循环的元素,而是调用一个长进程返回到更新的 GUI 元素,例如进度条或文本域。看起来这些元素只能从主 kivy 线程修改。我如何从外部访问它们?
最佳答案
按照描述使用发布者/消费者模型 here .这是该链接中的一个示例,已修改为使用单独的线程:
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()
关于 python 基维 : Properly start a background process that updates GUI elements,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26302572/