Kivy弹出窗口在单独的线程中运行 [英] Kivy popup running in separate thread

查看:61
本文介绍了Kivy弹出窗口在单独的线程中运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am populating a treeview in Kivy that takes some time depending on how large it is.

在树很大并且需要一段时间的情况下,我想在填充时显示一个弹出窗口,以便用户知道程序尚未冻结,并在填充树的逻辑结束时关闭该弹出窗口.

In the case the tree is large and takes awhile, I would like to display a popup while it is populating so the user is aware the program has not frozen, and close this popup when the logic for populating the tree finishes.

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

Here is what I have come up with through some research on the topic, but the popup still seems to only come once the tree is finished populating:

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

我尝试了一次奇异的Clock尝试,以防万一,这更符合我所寻找的内容,但是目前,它只会打开弹出窗口,而不会填充树.我是GUI编程和事件回调的新手,所以非常感谢您的帮助.

I included a kivy Clock attempt in case that is more on the right track of what I am looking for, however currently it will just open the popup and never populate the tree. I am new to GUI programming and event callbacks, so any help is greatly appreciated.

我尝试使代码简短,如果需要更多代码,请告诉我.

I tried keeping the code short, if more is needed please let me know.

推荐答案

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

I built an app which does something similar to what you're doing (different computation, but as you said the point was it was time-consuming and you want to thread a popup that shows the app isn't crashed - it's just crankin' the numbers). What ended up working for me was to set up a button to execute a dummy function which toggles both the popup and the calculation. Run the popup first and then thread the calculation through the 'from threading import Thread' module to execute the computation on a separate thread.

这是一个可行的例子.它只是睡眠了5秒钟,但是您可以将计算坚持到该函数中,并且应该可以正常工作.它的作用是在计算之前打开弹出窗口,并在计算完成后关闭弹出窗口.另外,您可以将"Loading.gif"文件粘贴到该文件夹​​中,如果您想使用除kivy以外的其他东西(实际上是用于加载Loading.gif的加载gif),它将把它作为加载gif导入.正在加载,因为它不存在...哈哈).如果用户厌倦了等待,还添加了取消"按钮.

Here's a working example. It's just sleeping for 5 seconds but you can stick your computation into that function and it should work just fine. What it does is opens the popup before the computation and closes the popup when the calculation is done. Also, you can stick a 'Loading.gif' file into the folder and it'll import that as your loading gif if you want to use something other than what kivy pulls up (which is essentially a loading gif for loading your Loading.gif which isn't loading because it's not there... haha). Also added an 'ABORT' button if your user gets tired of waiting.

最后,作为一个补充说明,我很难将.kv文件构建到pyinstaller应用程序Bundeler中,因此,请注意,使用builder.load_string(KV)函数是一个很好的选择

Finally just as a side note, I've had difficulties getting the .kv file to build into the pyinstaller application bundeler, so just as a heads up, using the builder.load_string(KV) function is a good alternative for that.

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

这篇关于Kivy弹出窗口在单独的线程中运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆