Kivy - Progress Bar



When a GUI application is performing some process that is time consuming, there should be some mechanism to let the user know about its progress. The Progressbar widget in Kivy framework shows a visual representation of the progress of an ongoing task.

Kivy's progress bar widget only supports horizontal mode, and appears on the application window with incremental progress.

The Progressbar class is defined in the "kivy.uix.progressbar" module.

from kivy.uix.progressbar import ProgressBar
pb = Progressbar(**kwargs)

The Progressbar widget is a display-only widget, and doesn't have any interactive elements, as is doesn't raise and propagate any events.

To create an instance of Progressbar, you need to set its max property.

from kivy.uix.progressbar import ProgressBar
pb = ProgressBar(max=1000)

The widget has value property. You can assign it to any number less than its "max" property.

pb.value=100

However, since the progressbar class doesn't have any events and event handlers, we need to manually link the value property to some process.

It can be done by periodically reading the instantaneous value of an attribute of the progressive task, and update the value property of the progress bar.

Let us say we have a long for loop, that takes its next iteration after every one second.

for i in range(1000):
   time.delay(1)
   print (i)

We want to show the increment of I on the progress bar. So, we schedule a clock event that calls a function after every one second.

progev = Clock.schedule_interval(update_progress, 1.0)

After each second, the update_progesss() function updates the value property of the progress bar to the iteration counter i

def update_progress():
   pb.value = i

Example

Let us implement this approach in the following code. The GUI design contains two buttons and a label. When the start button is pressed, it loads a mp3 file into the Sound object. The length of the sound file is used as the max property of the progressbar

self.sound = SoundLoader.load('sample.mp3')
self.length = self.sound.length

As the play() method is invoked, we schedule an progress event as shown above.

self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)

The update_progress() method reads the pos property of the Sound object and uses it to update the value property of the progressbar

def update_progress(self, dt):
   if self.sound.state=='play':
      if self.prg.value < self.length:
         self.progress += 1 # Update value.
         self.prg.value=self.progress

Here is the complete code

from kivy.app import App
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.core.audio import SoundLoader
from kivy.uix.progressbar import ProgressBar
from kivy.properties import NumericProperty
from kivy.core.window import Window

Window.size = (720, 400)

class audiodemoapp(App):
   length = NumericProperty(0.0)
   progress = NumericProperty(0.0)

   def build(self):
      layout = GridLayout(cols=1, padding=10)
      self.prg = ProgressBar()
      layout.add_widget(self.prg)
      self.l1 = Label(
         text='Press Start to Play', font_size=40,
         color=[.8, .6, .4, 1]
      )
      layout.add_widget(self.l1)
      box = BoxLayout(orientation='horizontal')
      self.button1 = Button(text="Start", font_size=32)
      self.button2 = Button(
         text='Pause', font_size=32,
         disabled=True
      )
      box.add_widget(self.button1)
      box.add_widget(self.button2)
      layout.add_widget(box)
      self.button1.bind(on_press=self.start_stop)
      self.button2.bind(on_press=self.pause_resume)
      
      return layout

   def start_stop(self, event):
      if self.button1.text == 'Start':
         self.l1.text = 'Playing'
         self.button1.text = 'Stop'
         self.sound = SoundLoader.load('sample.mp3')
         self.length = self.sound.length
         self.pos = 0
         self.button2.disabled = False
         self.sound.play()
         self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)
      else:
         if self.button1.text == 'Stop':
            self.l1.text = 'Press Start to Play'
            self.sound.state = 'stop'
            self.button1.text = 'Start'
            self.sound.unload()
            self.button2.disabled = True
            self.pos = 0
   
   def pause_resume(self, event):
      if self.button2.text == 'Pause':
         self.button2.text = 'Resume'
         self.l1.text == 'Paused'
         self.pos = self.sound.get_pos()
         self.sound.stop()
      else:
         if self.button2.text == 'Resume':
            self.l1.text = 'Playing'
            self.button2.text = 'Pause'
            print(self.pos)
            self.sound.seek(self.pos)
            self.sound.play()
            self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)
   def update_progress(self, dt):
      if self.sound.state == 'play':
         if self.prg.value < self.length:
            self.progress += 1 # Update value
            self.prg.value = self.progress
         else: # End case.
            self.progress = 0 # Reset value
            self.prog_ev.cancel() # Stop updating
   
audiodemoapp().run()

Output

Run the above code. Press the start button. The progress bar on top shows the instantaneous playing position of the the music file.

Kivy Progress Bar
Advertisements