问题
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()
回答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()
来源:https://stackoverflow.com/questions/56812777/triggering-popup-dismiss-in-a-method-which-didnt-call-popup-open-kivy