Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Kivy:正确启动更新GUI元素的后台进程_Python_Event Handling_Kivy - Fatal编程技术网

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

Python Kivy:正确启动更新GUI元素的后台进程,python,event-handling,kivy,Python,Event Handling,Kivy,我有一个Python脚本,它对用户文件执行一些密集的处理,可能需要一些时间。我使用Kivy为它构建了一个用户界面,允许用户选择文件、处理模式,并在处理过程中向他们显示一些消息 我的问题是,当主Kivy循环通过调用底层用户界面时,窗口冻结 据我所知,解决这个问题的正确方法是创建一个单独的进程,脚本将卸载到该进程,并从该进程向用户界面发送更新 然而,我找不到一个如何执行此操作的示例,也找不到关于如何将消息从单独的线程发送回应用程序的任何规范 有人能给我举个例子说明如何正确地做到这一点,或者给我指一下

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

我的问题是,当主Kivy循环通过调用底层用户界面时,窗口冻结

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

然而,我找不到一个如何执行此操作的示例,也找不到关于如何将消息从单独的线程发送回应用程序的任何规范

有人能给我举个例子说明如何正确地做到这一点,或者给我指一下与该主题相关的文档吗

更新:


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

使用所述的发布者/消费者模型。下面是修改为使用单独线程的链接的示例:

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()

请注意:虽然从另一个线程修改kivy属性名义上是可行的,但有各种迹象表明这不是线程安全的操作。使用调试器并在后台线程中逐步执行append函数。声明不应以这种方式修改属性。

这是一个很好的示例,我已经阅读了他们的文档。问题是我必须将主应用程序对底层脚本的调用分割开来。这正是我想要避免的。我有一个监视消息并将它们发送回GUI的观察器,但它不会在GUI中添加元素,它只是修改元素的属性,例如前进栏值或文本字段文本。在这种情况下,来自线程的信号似乎无法返回到主线程。如何避免这种情况?您可以尝试在主线程中使用调度回调调用。例如: