amjada
amjada

Reputation: 11

tkinter progressbar not updating in time

I have made a script that calles certain functions. After every function I want to update my progress bar. This is my code of the progressbar:


class loading(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        s = ttk.Style()
        s.theme_use('clam')
        s.configure("red.Horizontal.TProgressbar", foreground='red', background='red')

        self.progress = ttk.Progressbar(self, style="red.Horizontal.TProgressbar", orient='horizontal',
                                   length=101, mode='determinate')
        self.progress.pack(pady=10)

    def updateprogress(self):
        self.progress.step(20)
        return

But when I try to call update progress after my script functions, it doesnt update untill the very end. So after all my functions are finished, the progress bar goes from 0 to 100 instead of with steps.

        loading.updateprogress()
        script.install_requerement()
        loading.updateprogress()
        script.clone_vuestore_front()
        loading.updateprogress()

How can I fix this?

EDIT: I tried to use threads in my code. I will post the whole script this time:

#!/usr/bin/python
import subprocess
import os
from threading import Thread
from tkinter import ttk
import tkinter as tk
import time


class Application(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        self.wm_geometry('700x400')
        self.title('Install and integrate Vue Storefront')
        self._frame = None
        self.switch_frame(first_page)

    def switch_frame(self, frame_class):
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()
        return self._frame



class loading(tk.Frame):
    number=10
    def __init__(self, master):
        tk.Frame.__init__(self, master)

    def t_create_progress_bar(self):
        progress_bar = ttk.Progressbar(self, orient="horizontal", length=400)
        progress_bar.pack()

        progress_bar.after(1, self.t_loop_progress_bar, progress_bar)

        self.mainloop()

    def t_loop_progress_bar(self, progress_bar):
        progress_bar["value"] = self.number
        # Update it again in 100ms
        progress_bar.after(100, self.t_loop_progress_bar, progress_bar)


class first_page(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        t = tk.Message(self, width=500,
                       text='first page')
        t.pack()
        tk.Button(self, text='Accept', command=lambda: \
            self.AcceptClick(master)).pack(side=tk.RIGHT,
                                           padx=5, pady=5)

    def AcceptClick(self, master):
        loadingclass =  master.switch_frame(loading)
        thread = Thread(target=loadingclass.t_create_progress_bar(), daemon=True)
        thread.start()

        loadingclass.number = 0  # 0% done
        subprocess.run('sudo apt-get update', shell=True)
        loadingclass.number = 25  # 25% done
        subprocess.run('apt install nodejs', shell=True)
        loadingclass.number = 50  # 50% done
        subprocess.run('sudo apt-get update', shell=True)
        loadingclass.number = 75  # 75% done


if __name__ == '__main__':
    app = Application()
    app.mainloop()

The frame does switch and I see the progress bar. But now the script runs the subproccesses after i close the window instead I want to run a function, then update the progress bar.

What did I do wrong?

Upvotes: 1

Views: 3357

Answers (1)

Dan
Dan

Reputation: 36

As @TheLizzard suggested, try to change all local variables to static self vars. Also try to call root.update() when you update progress bar value (after self.progressbar.step(...)). Because root.mainloop(), as far as I know, is sync, that's why if you call it after your sync code, progressbar is updated only after this, and if you call it before - It'll just stop the code below.

Upvotes: 1

Related Questions