Try this:
from threading import Thread
from tkinter import ttk
import tkinter as tk
import time
progress = 0
def t_create_progress_bar():
# Don't use a `tk.Toplevel` here
root = tk.Tk()
root.resizable(False, False)
progress_bar = ttk.Progressbar(root, orient="horizontal", length=400)
progress_bar.pack()
progress_bar.after(1, t_loop_progress_bar, progress_bar)
root.mainloop()
def t_loop_progress_bar(progress_bar):
progress_bar["value"] = progress
# Update it again in 100ms
progress_bar.after(100, t_loop_progress_bar, progress_bar)
# Start the new thread
thread = Thread(target=t_create_progress_bar, daemon=True)
thread.start()
progress = 0 # 0% done
Subprocess.call("brew install node")
progress = 25 # 25% done
Subprocess.call("pip install tensorflow")
progress = 50 # 50% done
Subprocess.call("pip install pytorch")
progress = 75 # 75% done
Subprocess.call("pip install django")
It implements a progress bar that is inside the new thread. tkinter isn't going to crash as long as we don't use it inside the main thread. That is why I have a global variable progress that is incremented in the main thread and the progress bar is updated in the new thread. The new thread is updated every 100ms using a .after loop.
Note that all of the variables that start with t_ are only supposed to be accessed by the new thread and not the main thread.
Edit: The variable progress is out of 100
subprocesswill create a new process. Communicating with the other process can be very very hard. Why don't you use a thread from thethreadinglibrary?