0

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

Michael Green
  • 719
  • 6
  • 15

1 Answers1

1

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

Erik
  • 1,196
  • 2
  • 9
  • 18
  • Thanks for the quick response; tried the suggestion mentioned but it's throwing the following error: App.get_running_app().pop.dismiss() AttributeError: 'graphics' object has no attribute 'pop' – Michael Green Jun 28 '19 at 21:36
  • Oops, I went too quickly for your code. You need to initialize the popup in the `graphics` class, then use `App.get_running_app()` in your `MetaLevel` class. I updated the answer! – Erik Jun 28 '19 at 21:44