In my Kivy app, I have a function that takes a long time to complete. I made a popup to inform the user the function is running. I want to have a gif animation so that the user knows the app did not crash. In testing, the gif played as expected in the popup, until I add the long running function, then only a stationary image is displayed. Everything else works as expected (e.g. the popup closes at the end of the function).
tl;dr
How can I make a gif continue to play in my kivy app while a function is being executed?
Code Summary
I largely followed the code provide by Dirty Penguin's answer in Building a simple progress bar or loading animation in Kivy?:
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
from kivy.clock import Clock
import time, threading
class RunningPopup(GridLayout):
fpop = None
def set_pop(self, pwin):
self.fpop = pwin
def close(self):
self.fpop.dismiss()
class ExampleApp(App):
def show_popup(self):
self.pop_up = RunningPopup()
self.pop_up.open()
def process_button_click(self):
# Open the pop up
self.show_popup()
# the original code suggested by dirty penguin
# mythread = threading.Thread(target=self.really_long_function)
# mythread.start()
# I've had better luck with the Clock.schedule_once
Clock.schedule_once(self.really_long_function)
def really_long_function(self):
thistime = time.time()
while thistime + 5 > time.time(): # 5 seconds
time.sleep(1)
# Once the long running task is done, close the pop up.
self.pop_up.dismiss()
if __name__ == "__main__":
ExampleApp().run()
My KV file:
<RunningPopup>:
rows: 3
Label:
size_hint_y: 0.2
text: 'Experiments are running ... '
bold: True
color: hex('#0DB14B')
Label:
size_hint_y: 0.2
text: 'Please be patient, this may take time.'
color: hex('#0DB14B')
Image:
size_hint_y: 0.6
id: loading_animation_gif
height: dp(200)
source: './graphics/loading.gif'
center_x: self.parent.center_x
center_y: self.parent.center_y
allow_stretch: True
size_hint_y: None
anim_delay: 0.05
mipmap: True
Tried
Related
Using the Thread
will work. Here is a modified version of your code that uses threading. I had to make a few changes just to get your code to run:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.popup import Popup
import time, threading
kv = '''
#:import hex kivy.utils.get_color_from_hex
Button:
text: 'doit'
on_release: app.process_button_click()
<RunningPopup>:
GridLayout:
rows: 3
Label:
size_hint_y: 0.2
text: 'Experiments are running ... '
bold: True
color: hex('#0DB14B')
Label:
size_hint_y: 0.2
text: 'Please be patient, this may take time.'
color: hex('#0DB14B')
Image:
size_hint_y: 0.6
id: loading_animation_gif
height: dp(200)
source: 'elephant.gif' # my gif file
center_x: self.parent.center_x
center_y: self.parent.center_y
allow_stretch: True
size_hint_y: None
anim_delay: 0.05
mipmap: True
'''
class RunningPopup(Popup):
fpop = None
def set_pop(self, pwin):
self.fpop = pwin
def close(self):
self.fpop.dismiss()
class ExampleApp(App):
def build(self):
return Builder.load_string(kv)
def show_popup(self):
self.pop_up = RunningPopup()
self.pop_up.open()
def process_button_click(self):
# Open the pop up
self.show_popup()
# the original code suggested by dirty penguin
mythread = threading.Thread(target=self.really_long_function)
mythread.start()
# I've had better luck with the Clock.schedule_once
# Clock.schedule_once(self.really_long_function)
def really_long_function(self, *args):
thistime = time.time()
while thistime + 5 > time.time(): # 5 seconds
time.sleep(1)
# Once the long running task is done, close the pop up.
self.pop_up.dismiss()
if __name__ == "__main__":
ExampleApp().run()