I thought about displaying the progress of the function with the progress bar widget installed in Kivy's pop-up widget. By using the function for which you want to display the progress as a generator, it looks as if the progress bar is being updated from within the function.
Use the following image pop-up consisting of three parts: progress bar, label, and button.
In addition, the following two methods have been added to the pop-up widget.
set_value ()
: Method to update the value and label of the progress barThe code is as follows.
Class-PopupProgress
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.progressbar import ProgressBar
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.label import Label
class PopupProgress():
def __init__(self, value_init=0, value_max=1, title='', size=None,
auto_close=False):
self._auto_close = auto_close
self._box = BoxLayout(orientation='vertical')
if size is None:
size_hint = (1,1)
else:
size_hint = (None, None)
self.popup = Popup(title=title,
content=self._box,
auto_dismiss=False,
size_hint=size_hint,
size=tuple(size)
)
# progress bar
self._pb = ProgressBar(max=value_max, value=value_init)
self._box.add_widget(self._pb)
# label
self._label = Label(text='')
self._box.add_widget(self._label)
# close button
self._button = Button(text='Close', height=40, size_hint_y=None,
disabled=True)
self._button.bind(on_press=self.popup.dismiss)
self._box.add_widget(self._button)
self.popup.open() #Open a pop-up
def set_value(self, value=None, message=''):
if not value is None:
self._pb.value = value
self._label.text = message
if self._pb.value_normalized>=1:
if self._auto_close:
self.popup.dismiss()
else:
self.enable_close_button()
def enable_close_button(self):
self._button.disabled = False
Root Widget In addition to the constructor (\ _ \ _ init \ _ \ _) for creating buttons, the Root Widget has the following three methods.
func_test ()
: Method (generator) that wants to check the progress of time-consuming processing--The method that wants to check the progress of time-consuming processing is a generator. --The
yield value, message
is inserted in the place where you want to check the progress of the process, and the progress and message are returned. --At the end of the process,value = 1
is returned and the close button is enabled. --Here, Max value = 1 of the progress bar is set, but any value can be set withfunc_test_pp ()
. --Here,time.sleep (1)
is set to imitate the time-consuming process.
func_test_pp ()
: Method to start a loop to update the value of the progress bar--Create an instance of the pop-up widget class
self.pp
. --Create an iterator objectself.gen
from the abovefunc_test ()
generator. --Use theClock.schedule_once ()
to execute the recursive methodpp_update ()
to start the loop.
pp_update ()
: Recursive method to update the value of the progress bar--After referencing the iterator object
self.gen
once, update the value of the progress bar. --UseClock.schedule_once ()
to call itself again until you get aStopIteration
or other error. --If an error occurs, the button in the pop-up is enabled so that the user can close the pop-up.
Clock.schedule_once ()
was unstable at 0 seconds, it is set to be executed after 0.1 seconds for the time being.Class-RootWidget etc.
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
import time
class RootWidget(BoxLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
button = Button(text='popup!')
button.bind(on_press=self.func_test_pp)
self.add_widget(button)
def pp_update(self, *args):
try:
value, message = next(self.gen)
self.pp.set_value(value, message)
Clock.schedule_once(self.pp_update, 0.1)
except StopIteration:
self.pp.enable_close_button()
except Exception as e:
self.pp.set_value(message=str(e))
self.pp.enable_close_button()
def func_test_pp(self, *args):
self.pp = PopupProgress(
title='TestPopupProgress',
size=(self.width/2, self.height/3)
)
self.gen = self.func_test()
Clock.schedule_once(self.pp_update, 0.1)
def func_test(self):
yield 0, 'Preparing...' #Use yield to return current progress and comments (beginning)
#Time-consuming processing that you want to check the progress
allitems = 5
for i in range(allitems):
time.sleep(1) #Something time-consuming process
yield (i+1)/allitems, '{:d}/{:d}'.format(i+1, allitems) #Use yield to return current progress and comments
yield 1, 'Complete.' #Use yield to return current progress and comments (end)
class TestPopupProgressApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
TestPopupProgressApp().run()
The above can be summarized as follows.
test_popup_progress.py
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.progressbar import ProgressBar
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.label import Label
import time
class PopupProgress():
def __init__(self, value_init=0, value_max=1, title='', size=None,
auto_close=False):
self._auto_close = auto_close
self._box = BoxLayout(orientation='vertical')
if size is None:
size_hint = (1,1)
else:
size_hint = (None, None)
self.popup = Popup(title=title,
content=self._box,
auto_dismiss=False,
size_hint=size_hint,
size=tuple(size)
)
# progress bar
self._pb = ProgressBar(max=value_max, value = value_init)
self._box.add_widget(self._pb)
# label
self._label = Label(text='')
self._box.add_widget(self._label)
# close button
self._button = Button(text='Close', height=40, size_hint_y=None,
disabled=True)
self._button.bind(on_press=self.popup.dismiss)
self._box.add_widget(self._button)
self.popup.open()
def set_value(self, value=None, message=''):
if not value is None:
self._pb.value = value
self._label.text = message
if self._pb.value_normalized>=1:
if self._auto_close:
self.popup.dismiss()
else:
self.enable_close_button()
def enable_close_button(self):
self._button.disabled = False
class RootWidget(BoxLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
button = Button(text='popup!')
button.bind(on_press=self.func_test_pp)
self.add_widget(button)
def pp_update(self, *args):
try:
value, message = next(self.gen)
self.pp.set_value(value, message)
Clock.schedule_once(self.pp_update, 0.1)
except StopIteration:
self.pp.enable_close_button()
except Exception as e:
self.pp.set_value(message=str(e))
self.pp.enable_close_button()
def func_test_pp(self, *args):
self.pp = PopupProgress(
title='TestPopupProgress',
size=(self.width/2, self.height/3)
)
self.gen = self.func_test()
Clock.schedule_once(self.pp_update, 0.1)
def func_test(self):
yield 0, 'Preparing...'
allitems = 5
for i in range(allitems):
time.sleep(1)
yield (i+1)/allitems, '{:d}/{:d}'.format(i+1, allitems)
yield 1, 'Complete.'
class TestPopupProgressApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
TestPopupProgressApp().run()
Recommended Posts