Michael Green
Michael Green

Reputation: 820

triggering Popup.dismiss() in a method which didn't call Popup.open() (kivy)

I'm trying to develop a kivy app for my less-comp-savvy colleagues which wraps a nice GUI around some computations which I developed for a project; currently I have two methods embedded in a class, one (called 'dummy') which keeps the GUI from freezing and from such multithreads the second method (called 'calculate') which actually runs the computation. Within the dummy method I'm hoping to open a popup which displays a 'loading GIF' (indicating that the program is running and not just frozen), and I want the popup to close upon the completion of the 'calculate' method. How can I bind the automatic closing of the popup to the completion of the method 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()

--- Edit 1---

Still working on trying to solve the problem; I came across the Clock.create_trigger() function and tried integrating that into the Pop class - issue is that I'm unable to figure out how to call the trigger() after main() in the calculate method (See below). Might be a viable solution to the problem if we can get the trigger to fire.

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

Upvotes: 0

Views: 327

Answers (1)

Erik
Erik

Reputation: 1226

Try assigning your popup to a variable in your class which inherits from App (I'll call this your "main app class"). You can reference variables and functions from within your main app class by using App.get_running_app().your_variable in Python or simply app.your_variable in the kv language.

For your case, remove the line in GUI.py Pop().open() and replace it with the following line:

App.get_running_app().pop.open()

Then in your graphics class, create a variable for the popup. You can do this in the build function, just add self.pop = Pop()

Now, in your calc.py program, you will need to add from kivy.app import App, then at the end of your main function, add the line to dismiss the popup:

App.get_running_app().pop.dismiss()

Upvotes: 1

Related Questions