在未调用 Popup.open() 的方法中触发 Popup.dismiss() (kivy)

Posted

技术标签:

【中文标题】在未调用 Popup.open() 的方法中触发 Popup.dismiss() (kivy)【英文标题】:triggering Popup.dismiss() in a method which didn't call Popup.open() (kivy) 【发布时间】:2019-11-10 18:12:51 【问题描述】:

我正在尝试为我的不太懂计算的同事开发一个 kivy 应用程序,它为我为一个项目开发的一些计算包装了一个漂亮的 GUI;目前我在一个类中嵌入了两种方法,一种(称为“dummy”)可以防止GUI冻结,第二种方法(称为“calculate”)实际上运行计算。在虚拟方法中,我希望打开一个显示“加载 GIF”的弹出窗口(表明程序正在运行,而不仅仅是冻结),并且我希望在“计算”方法完成后关闭弹出窗口。如何将弹出窗口的自动关闭绑定到方法calculate(self, *args)的完成?

-- GUI.py--

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
import threading
from calc import main


class Pop(Popup):
    pass


class MetaLevel(GridLayout):
    def dummy(self, *args):
        Pop().open()
        threading.Thread(target=self.calculate, args=(args,)).start()

    def calculate(self, *args):
        main()


class graphics(App):
    def build(self):
        return MetaLevel()


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

-- calc.py--

def main():
    import numpy as np
    from pathos.multiprocessing import ProcessPool as Pool

    grid = np.array([(m, n)
                     for m in np.arange(1, 100, 1)
                     for n in np.arange(1, 100, 1)])

    def calc(grid):
        var1 = grid[0]
        var2 = grid[1]
        y = var1*var2
        return y

    res = Pool().map(calc, grid)
    print('done')
    # data output from res here

--graphics.kv--

<Button>:
    font_size: 12

<MetaLevel>:
    id: calculator
    rows: 5
    padding: 10
    spacing: 10

    BoxLayout:
        height: 10
        Label:
            spacing: 10
            text: 'test'

    BoxLayout:
        Button:
            id: run_button
            text: "Run"
            on_release: root.dummy()

--- 编辑 1---

仍在努力解决问题;我遇到了 Clock.create_trigger() 函数并尝试将其集成到 Pop 类中 - 问题是我无法弄清楚如何在计算方法中的 main() 之后调用 trigger()(见下文)。如果我们可以触发触发器,可能是解决问题的可行方案。

--GUI.py--


from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
import threading
from kivy.clock import Clock
from calc import main


class Pop(Popup):
    def __init__(self, **kwargs):
        super(Pop, self).__init__(**kwargs)
        trigger = Clock.create_trigger(self.dismiss_popup)

    def dismiss_popup(self, dt):
        self.dismiss()


class MetaLevel(GridLayout):
    def dummy(self, *args):
        Pop().open()
        threading.Thread(target=self.calculate, args=(args,)).start()

    def calculate(self, *args):
        main()
        trigger() # after main finishes I want to toggle the trigger, but kivy/python doesn't like this



class graphics(App):
    def build(self):
        return MetaLevel()


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

【问题讨论】:

【参考方案1】:

尝试将您的弹出窗口分配给您的类中的一个变量,该变量继承自 App(我将其称为您的“主应用程序类”)。您可以通过在 Python 中使用 App.get_running_app().your_variable 或在 kv 语言中使用 app.your_variable 从主应用程序类中引用变量和函数。

对于您的情况,删除 GUI.py 中的行 Pop().open() 并将其替换为以下行:

App.get_running_app().pop.open()

然后在您的graphics 类中,为弹出窗口创建一个变量。您可以在build 函数中执行此操作,只需添加self.pop = Pop()

现在,在您的calc.py 程序中,您需要添加from kivy.app import App,然后在您的main 函数的末尾添加一行以关闭弹出窗口:

App.get_running_app().pop.dismiss()

【讨论】:

感谢您的快速回复;尝试了提到的建议,但它引发了以下错误:App.get_running_app().pop.dismiss() AttributeError: 'graphics' object has no attribute 'pop' 糟糕,我的代码太快了。您需要在graphics 类中初始化弹出窗口,然后在您的MetaLevel 类中使用App.get_running_app()。我更新了答案!

以上是关于在未调用 Popup.open() 的方法中触发 Popup.dismiss() (kivy)的主要内容,如果未能解决你的问题,请参考以下文章

在未选择的选项卡中从片段调用方法

在未初始化的对象(空指针)上调用方法

无法在未安装的组件上调用 setState

如何防止 jQuery 悬停事件在未完成时触发?

如何在 jQuery Mobile 中等待弹出窗口关闭?

Swift inout 如何在未更改时不复制回属性,以不触发对象设置器