Is it possible for a ProgressBar reaching 100% once another function finishes?

Viewed 618

so basically, i would like to make the Progressbar(Tkinter's widget) reach 100%, once the other function i am running finishes. Right now i am using threading to make them run in parallel, and i have calculated how long it takes for the function to finish, and i have set up the progressbar accordingly. But what about when the function doesn't take a set amount of time, and it could get either 5 secs or 3 minutes?

from threading import Thread
import serial
import tkinter as tk
from tkinter import *
import re
from time import sleep
import time



ser = serial.Serial('COM3', timeout=1)
ser.baudrate = 115200
maxTemp = 85

def bar():
    import time
    progress['value'] = 0
    mainWindow.update_idletasks()
    time.sleep(1)

    progress['value'] = 20
    mainWindow.update_idletasks()
    time.sleep(1)

    progress['value'] = 40
    mainWindow.update_idletasks()
    time.sleep(1)

    progress['value'] = 50
    mainWindow.update_idletasks()
    time.sleep(1)

    progress['value'] = 60
    mainWindow.update_idletasks()
    time.sleep(1)

    progress['value'] = 80
    mainWindow.update_idletasks()
    time.sleep(1)
    progress['value'] = 100


def testmode_login():
    #the function is too big so i won't write it, it could take from 3 secs, to 50 secs to finish.

def parallel_run():
    if __name__ == '__main__':
        Thread(target=bar2).start()
        Thread(target=testmode_login).start()


1 Answers

The easy solution would be to have your running Thread set a variable (an attribute or a global variable) to keep track of the progress. You didn't show the content of the worker function, so I'll assume that you have some kind of loop inside, which could be used to track the progress.

If your tkinter code is only reading from that global variable, you shouldn't have any issue. Here's an example of that happening:

import tkinter as tk
import tkinter.ttk as ttk
import time
import threading


class Worker(threading.Thread):
    def __init__(self, variable, **kwargs):
        super().__init__(**kwargs)
        self.variable = variable

    def run(self):
        for i in range(101):
            self.variable.set(i)
            time.sleep(1)


class MainWindow(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.progress = tk.IntVar()
        self.progress.set(0)
        self.pbar = ttk.Progressbar(self, orient="horizontal", length=300,
                                    variable=self.progress, mode="determinate",
                                    maximum=100)
        self.pbar.pack()
        self.but = tk.Button(self, text="Start", command=self._start_thread)
        self.but.pack()

    def _start_thread(self):
        Worker(self.progress).start()


root = tk.Tk()
root.title("Pbar Example")
gui = MainWindow(root)
gui.pack()
root.mainloop()

Instead of just using a worker function, I've made a threading.Thread instance, but the idea stays the same. If you want to work with functions, you just have to pass in the tkinter variable as an argument to that function.

The progressbar takes a variable argument, which in this case is more appropriate than setting the value directly, since you don't have to update your gui everytime, tkinter will do it for you when the variable changes.

In this example, tkinter only reads the value of the variable, otherwise you'd have some concurrency issues. Tkinter variable are also passed as references (think of them as list).

Related