Search code examples
pythonkivykivy-language

Kivy progress bar value updates, but progress bar does not


I have a ProgressBar in my kivy app. I believe I need to use Clock.create_trigger to ensure the progress bar updates from inside of a loop.

I've attempted to adapt the solutions from Progress bar in kivy can't update using loop and Kivy How can i create time counter with progressbar? for my solution, however, the bar still does not update until the very end.

The following code is a watered-down version for reproducibility purposes.

ProgressBar Class

from kivy.clock import Clock
from kivy.uix.progressbar import ProgressBar


class MyProgressBar(ProgressBar):
    def __init__(self, *args, **kwargs):
        super(MyProgressBar, self).__init__(*args, **kwargs)
        # self.update_bar_trigger = Clock.create_trigger(self.update_bar)
        self.update_bar_trigger = Clock.create_trigger(lambda dt: self.update_bar(), 1)

    def update_bar(self, step):
        if self.value <= 100:
            self.value += step
            self.update_bar_trigger()

Main class:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from MyProgressBar import MyProgressBar

from kivy.lang import Builder
Builder.load_file('style.kv')


class Main_app(BoxLayout):
    # Progress bars
    loading_pb = MyProgressBar()

    def dummy(self):
        pb_increment = 10

        for i in range(10):
            time.sleep(2)
            self.loading_pb.update_bar(pb_increment)
            print(self.loading_pb.value)


class Stacked(App):
    def build(self):
        Window.clearcolor = (1, 1, 1, 1)
        Window.size = (1000, 700)

        return Main_app()

if __name__ == '__main__':
    Stacked().run()

KV File

<Main_app>:
    loading_pb: load_pb

    GridLayout:
        rows: 2
        MyProgressBar:
            id: load_pb
            value: 0
            min: 0
            max: 100

        Button:
            text: 'Start Progress Bar'
            on_press:
                root.dummy()

This example shows loading_pb.value changing as the code loops through after the button is clicked.

ProgressBar.value printed output

10.0
20.0
30.0
40.0
50.0
60.0
70.0
80.0
90.0
100.0

Problem The progress bar value does seem to increment as expected, but the actual progress bar does not change until all at once, at the end of the loop.

gif of progress bar not updating

Related


Solution

  •     for i in range(10):
            time.sleep(2)
            self.loading_pb.update_bar(pb_increment)
            print(self.loading_pb.value)
    

    This bit of code blocks the gui until it returns, so none of the normal gui drawing takes place. Instead, use Clock.schedule_interval and/or Clock.schedule_once to schedule each iteration of the loop. These insert the function call into kivy's own eventloop, and avoid blocking that loop.