[PYTHON] GUI programming using kivy ~ Part 2 Progress bar ~

Introduction

In the previous introduction, as the name suggests, we explained about Kivy, built the environment, and executed the sample program. This time, I would like to introduce the progress bar when doing something. It seems to be a little niche article that feels like a title scam, but please forgive me. I think that the article will be like this from the next time w

What is a progress bar?

As you all know, [wikipedia](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%AC%E3 % 82% B9% E3% 83% 90% E3% 83% BC) I will quote the outline.

The progress bar (English: Progress Bar) is one of the elements (widgets) of the graphical user interface, which visually and intuitively displays how much the progress of a task that takes a long time has been completed. .. Often used when displayed in percentage format, such as downloads and file transfers. Also known as Progress Meters.

It's such a guy. (This image is also [wikipedia](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%AC%E3%82% From B9% E3% 83% 90% E3% 83% BC))

When I implemented some time-consuming behavior in kivy, I wanted a progress bar, Kivy Reference has almost no explanation. I ended up wandering around the net. .. ..

How to use the progress bar in kivy

It works like this.

pb1.gif

The source is as follows.

from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.progressbar import ProgressBar

class ProgressTest(BoxLayout):
    def __init__(self, **kwargs):
        super(ProgressTest, self).__init__(**kwargs)
        #Progress bar widget
        self.pb = ProgressBar()
        self.add_widget(self.pb)
        
        #Process start button widget
        button_pb = Button(text='progress')
        #Associate processing with a button
        button_pb.bind(on_press=self.test_progress)
        self.add_widget(button_pb)

    #Repeat the process at regular intervals
    def pb_clock(self,dt):
        #Stops the clock when the progress bar reaches its maximum value
        if self.pb.value == 100:
            return False
        #Increase the value of the progress bar
        self.pb.value += 1

    def test_progress(self, *args):
        self.pb.value = 0
        #Clock start
        Clock.schedule_interval(self.pb_clock, 1/60)

class TestProgress(App):
    def build(self):
        return ProgressTest()


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

The important thing is the processing of Clock. Even if the value of the progress bar is updated with the for statement or the value of the value itself is updated, the progress bar on the screen does not change until the for processing is completed. Therefore, we use Clock, which is called sequentially every time of kivy and draws the screen.

I wrote the above source as a usage, but considering that the progress bar is actually used, I feel that it is often embedded in a pop-up or something.

Also, in the above program, it is necessary to write the process you want to perform in the Clock process, In order to visualize the progress of iterative processing of the existing class, I think that the for statement needs to be rewritten for Clock.

Therefore, we will further customize it so that the progress of processing from the external class can be visualized on the pop-up.

What you want to make

This time, I would like to implement a process to operate two progress bars at the same time on the popup. The image looks like the figure below.

イメージ.png

A function of another class is used as a sub process, and the main process is completed after each sub process. It is assumed that the progress bar will advance.

As mentioned in the usage chapter, if you perform a slightly longer process of the for statement in another class, the screen will become dark and the operation will not work. Official also has a description like this.

When I try to move the second program bar, even if the process itself is working, screen drawing is not accepted, and I can not tell if it is working only with the GUI.

Therefore, in order to force the screen to be drawn, the threading module of Python is used so that the screen can be drawn while processing. (I don't know if it's a straightforward approach, but it works fine.)

Source code

sample.py


from kivy.uix.progressbar import ProgressBar
from kivy.uix.popup import Popup
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button

import time
import threading

#Class assuming heavy processing
from NagaiSyori import longProc


class ProgressPop(BoxLayout):
    def __init__(self, **kwargs):
        super(ProgressPop, self).__init__(**kwargs)
        #Button to bring up a pop-up
        button_pb = Button(text='thread pop!!')
        button_pb.bind(on_press=self.open_pupup)
        self.add_widget(button_pb)
        #self.tmp = 0
        #Class that does heavy external processing
        self.sub_process = longProc()
        #Flag to end thread processing
        self.thread_flag = False

    #Pop-up screen and its processing
    def open_pupup(self, btn):
        #Pop-up screen base
        content = BoxLayout(orientation='vertical')
        self.pb = ProgressBar()
        content.add_widget(self.pb)
        self.sub_pb= ProgressBar()
        content.add_widget(self.sub_pb)
        self._close = Button(text="close",
                             on_press=self.dissmiss)
        content.add_widget(self._close)
        #Pop-up widget
        self._pup = Popup(title="Popup Test",
                          content=content,
                          size_hint=(0.5,0.5))
        #Open a pop-up
        self._pup.open()

        #Preparing for thread processing
        self.thread_flag = True
        self.ev = threading.Event()

        #Thread processing started
        self.thed = threading.Thread(target=self.test_progress)
        self.thed.start()

    #Processing when closing the pop-up
    def dissmiss(self, *args):
        self.ev.clear()
        self.thread_flag = False
        self._pup.dismiss()

    #Updated the value of the main progress bar
    def main_clock(self, *args):
        #Stops the clock when the progress bar value reaches its maximum
        if self.tmp >= 100:
            Clock.unschedule(self.main_clock)
        self.pb.value = self.tmp

    #Update the value of the sub progress bar
    def sub_clock(self, *args):
        #Stops the clock when the progress bar value reaches its maximum
        if self.sub_process.num >= 100:
            Clock.unschedule(self.sub_clock)
        self.sub_pb.value = self.sub_process.num

    #processing
    def test_progress(self):
        #Variables for passing values to the progress bar
        self.tmp = 0
        #Clock start to update the value to the progress bar
        Clock.schedule_interval(self.main_clock, 1 / 60)
        for i in range(20):
            #If all the processing is not finished
            if self.thread_flag:
                time.sleep(1/60)
                #Clock to update the value of the sub progress bar
                Clock.schedule_interval(self.sub_clock, 1 / 60)
                #Heavy processing
                self.sub_process.process()
                self.tmp = i*5 + 5
                print(self.tmp)
        #Thread termination processing when all processing is completed
        self.ev.clear()
        self.thread_flag = False

class TestPopupProgressApp(App):
    def build(self):
        return ProgressPop()


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

NagaiSyori.py


import time
class longProc:
    def __init__(self):
        #Variables for passing values to the progress bar
        self.num = 0

    #Heavy processing
    def process(self):
        self.num = 0
        for i in range(100):
            time.sleep(1/600)
            self.num = i + 1

pb2.gif

If you execute it, it will work like this.

By adding thread processing, it is not necessary to write repetitive processing in Clock. In addition, it is now possible to visualize the processing status of external classes! !! !!

Reference article

It was very helpful. thank you very much.

Progress bar in pop-up with Python Kivy

Python | Progress Bar widget in kivy - GeeksforGeeks

Recommended Posts

GUI programming using kivy ~ Part 2 Progress bar ~
GUI programming using kivy ~ Part 6 Various layouts ~
GUI programming with kivy ~ Part 3 Video and seek bar ~
GUI programming with kivy ~ Part 5 Creating buttons with images ~
GUI programming in Python using Appjar
[Python] Progress display by progress bar using tqdm