Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Tkinter (ttk) dynamically create a progressbar with its own value that changes

So basicly I'm trying to make multiple progressbar and each progressbars value runs from 0 to 100. But right now my functions acess the values from the others too and that looks weird. Hopefully someone can help me. Thanks :)

# -*- coding: utf-8 -*-
import tkinter.ttk as ttk
import tkinter as tk
from threading import Thread
import time

class Main(object):
    def __init__(self, master):
        self.master = master

        self.frame = tk.Frame(self.master, width=400, height=400)
        self.frame.pack(expand=True)

        self.button = tk.Button(self.frame, text="Add Bar", command=self.start_thread)
        self.button.pack(fill="y")

    def start_thread(self):
        self.t = Thread(target=self.add_bar)
        self.t.start()

    def add_bar(self):
        self.var = tk.IntVar()
        self.var.set(0)

        self.progessbar = ttk.Progressbar(self.frame, variable=self.var, orient=tk.HORIZONTAL, length=200)
        self.progessbar.pack()

        self.add_values(self.var)

    def add_values(self, var):
        self.variable = var
        for self.x in range(100):
            time.sleep(0.1)
            self.variable.set(self.x)


root = tk.Tk()
app = Main(root)
root.mainloop()
like image 881
HealYouDown Avatar asked Mar 20 '26 10:03

HealYouDown


1 Answers

In your original code, self.var is the only variable storing the progress of the loading bar. Since there is only one instance of the Main object, there is only one instance of self.var which is resulting in the problem you described. In order to fix this, I recommend creating a separate class for the loading bar as shown below:

# -*- coding: utf-8 -*-
import tkinter.ttk as ttk
import tkinter as tk
from threading import Thread
import time

class Main(object):
    def __init__(self, master):
        self.master = master

        self.frame = tk.Frame(self.master, width=400, height=400)
        self.frame.pack(expand=True)

        self.button = tk.Button(self.frame, text="Add Bar", command=lambda:self.createBar())
        self.button.pack(fill="y")

    def createBar(self):
        self.t = Thread(target=self.create)
        self.t.start()

    def create(self):
        newBar = LoadingBar(self.master, self.frame)

class LoadingBar(object):
    def __init__(self, master, frame):
        # Must use same Tkinter frame to add loading bars into
        self.master = master
        self.frame = frame
        self.add_bar()

    def start_thread(self):
        self.t = Thread(target=self.add_bar)
        self.t.start()

    def add_bar(self):
        self.var = tk.IntVar()
        self.var.set(0)

        self.progessbar = ttk.Progressbar(self.frame, variable=self.var, orient=tk.HORIZONTAL, length=200)
        self.progessbar.pack()

        self.add_values(self.var)

    def add_values(self, var):
        self.variable = var
        for self.x in range(100):
            time.sleep(0.1)
            self.variable.set(self.x)

root = tk.Tk()
app = Main(root)
root.mainloop()

Creating each instance of the loading bar in a separate thread allows for the desired effect.

Here is another approach (no new class):

# -*- coding: utf-8 -*-
import tkinter.ttk as ttk
import tkinter as tk
from threading import Thread
import time

class Main(object):
    def __init__(self, master):
        self.master = master

        self.frame = tk.Frame(self.master, width=400, height=400)
        self.frame.pack(expand=True)

        self.button = tk.Button(self.frame, text="Add Bar", command=self.start_thread)
        self.button.pack(fill="y")

    def start_thread(self):
        self.t = Thread(target=self.add_bar)
        self.t.start()

    def add_bar(self):
        var = tk.IntVar()
        var.set(0)

        progessbar = ttk.Progressbar(self.frame, variable=var, orient=tk.HORIZONTAL, length=200)
        progessbar.pack()

        self.add_values(var)

    def add_values(self, var):
        variable = var
        for x in range(100):
            time.sleep(0.1)
            variable.set(x)


root = tk.Tk()
app = Main(root)
root.mainloop()

Note: local variables are created for each thread as opposed to instance variables to avoid the overwriting of instance variables.

like image 183
Advait Avatar answered Mar 22 '26 22:03

Advait



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!