【问题标题】:Kivy popup running in separate threadKivy 弹出窗口在单独的线程中运行
【发布时间】:2017-07-05 21:55:46
【问题描述】:

我正在 Kivy 中填充树视图,这需要一些时间,具体取决于它的大小。

如果树很大并且需要一段时间,我想在填充时显示一个弹出窗口,以便用户知道程序没有冻结,并在填充树的逻辑完成时关闭此弹出窗口。

这是我通过对该主题的一些研究得出的结论,但弹出窗口似乎仍然只有在树完成填充后才会出现:

def show(self, *args):
        self.error_popup.open()

def populate_tree(self, model):
        #Clock.schedule_once(self.error_popup.open())
        popup_thread = threading.Thread(target=self.show())
        popup_thread.start()

        # order the dictionary for better user experience 
        ordered_data = collections.OrderedDict(sorted(model.items()))

        # logic to populate tree
        for county, value in ordered_data.items():

            if county != "model_name":
                # set initial county dropdowns in tree
                county_label = self.treeview.add_node(TreeViewButton(text=str(county), on_press=self.edit_node))
                i = 0 # keep count of rules

                # add rules children to county
                for rule_obj, rule_list in value.items():
                    for rule in rule_list:
                        i += 1
                        # set rule number in tree
                        rule_label = self.treeview.add_node(TreeViewButton(text='Rule ' + str(i), on_press=self.edit_node), county_label)
                        # add conditions children to rule
                        for condition in rule:
                           self.treeview.add_node(TreeViewButton(text=condition, on_press=self.edit_node), rule_label)

        #Clock.schedule_once(self.error_popup.dismiss())
        #somehow close popup_thread

我包括了一个 kivy Clock 尝试,以防它更符合我正在寻找的内容,但目前它只会打开弹出窗口并且永远不会填充树。我是 GUI 编程和事件回调的新手,非常感谢任何帮助。

我尽量保持代码简短,如果需要更多,请告诉我。

【问题讨论】:

标签: python multithreading kivy


【解决方案1】:

我构建了一个应用程序,该应用程序的功能类似于您正在做的事情(不同的计算,但正如您所说的那样,它很耗时,并且您想要线程显示应用程序没有崩溃的弹出窗口 - 它是只是曲柄数字)。最终对我有用的是设置一个按钮来执行一个虚拟功能,该功能可以切换弹出窗口和计算。先运行弹窗,然后通过'from threading import Thread'模块将计算线程化,在单独的线程上执行计算。

这是一个工作示例。它只是休眠了 5 秒钟,但您可以将计算粘贴到该函数中,它应该可以正常工作。它的作用是在计算之前打开弹出窗口,并在计算完成后关闭弹出窗口。此外,您可以将“Loading.gif”文件粘贴到文件夹中,如果您想使用 kivy 拉起的内容以外的其他内容(本质上是用于加载 Loading.gif 的加载 gif),它将作为加载 gif 导入没有加载,因为它不在那里......哈哈)。如果您的用户厌倦了等待,还添加了一个“ABORT”按钮。

最后,顺便说一句,我很难将 .kv 文件构建到 pyinstaller 应用程序捆绑器中,因此请注意,使用 builder.load_string(KV) 函数是一个很好的替代方案.

from threading import Thread
from sys import exit
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.lang import Builder

KV = '''
<Pop>:
    id:pop
    title: ''
    auto_dismiss: False
    padding: 10
    spacing: 10

    BoxLayout:
        BoxLayout:
            padding: 10
            spacing: 10
            orientation: 'vertical'
            Label:
                font_size: 22
                size_hint_y: None
                text_size: self.width, None
                height: self.texture_size[1]
                text: "Process is currently running."
            Label:
                id: error_msg
                size_hint_x: 0.3
                text: ''

            BoxLayout:
                orientation: 'vertical'
                Button:
                    background_color: (1,0,0,1)
                    text: "ABORT"
                    on_press: root.sysex()

        AsyncImage:
            source: 'Loading.gif'

<MetaLevel>:
    rows: 1
    cols: 1
    Button:
        text: 'RUN'
        on_release: root.dummy()

'''

Builder.load_string(KV)

class MetaLevel(GridLayout):

    def dummy(self, *args):
        App.get_running_app().pop.open()
        Thread(target=self.calculate, args=(args,), daemon=True).start()

    def calculate(self, *args):
        import time
        time.sleep(5)
        App.get_running_app().pop.dismiss()


class Pop(Popup):
    def sysex(self):
        exit()


class Cruncher(App):
    def build(self):
        self.pop = Pop()
        return MetaLevel()


if __name__ == "__main__":
    Cruncher().run()

【讨论】:

    【解决方案2】:

    你能把这个排序吗?

    我认为如果您使用线程来填充树而不是使用它来显示弹出窗口,它会起作用。填充树后,在同一个线程中,您可以使用 Popup.dismiss() 关闭弹出窗口

    main.py 文件

    from kivy.app import App
    from kivy.uix.popup import Popup
    from kivy.uix.label import Label
    from kivy.uix.boxlayout import BoxLayout
    import time, threading
    
    class popupTestApp(App):
        def waitSec(self):
            time.sleep(5)
            self.p.dismiss()
    
        def popUpFunc(self):
            self.p = Popup(title='Test Popup', content=Label(text='This is a test'), size_hint=(None,None), size=(400,400))
            self.p.open()
            popUpThread = threading.Thread(target=self.waitSec)
            popUpThread.start()
    
    if __name__ == '__main__':
        popupTestApp().run()
    

    popuptest.kv 文件

    BoxLayout:
        BoxLayout:
            id:LeftPane
            Button:
                id:MyButton
                text:'Pop it up!'
                on_release:app.popUpFunc()
        BoxLayout:
            id:RightPane
            Label:
                text: 'Another Pane'
    

    请查看下面的链接,其中对此进行了很好的解释。

    Building a simple progress bar or loading animation in Kivy

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      相关资源
      最近更新 更多