Search code examples
pythontkintergrid-layoutttkpack

Issues using grid vs pack for ttk Progressbar


I'm trying to create a progressbar class that combines the standard progress bar with a label showing the percent the bar is filled in. This value can then be updated to show percent completion. The class itself works fine, but there are two issues with trying to place both the widgets in the class and the class itself.

When I use pack(side = tk.LEFT) the widgets pack correctly in the class. However, then when I use this class within my main program (which is managed by grid) the label vanishes.

Secondly, using grid() with correct column spacing in my class stacks the two widgets on top of each other, not side by side as intended. When trying to use the class within my main program, I get the error:

_tkinter.TclError: cannot use geometry manager pack inside . which already has slaves managed by grid

Code here:

import tkinter as tk
import tkinter.ttk as ttk

class ProgressBarPercent(tk.Frame):
    def __init__(self, parent, orient, length, mode):
        tk.Frame.__init__(self, parent)

        self.progress = ttk.Progressbar(self, orient = orient, 
              length = length, mode = mode)
        self.text = tk.StringVar()
        self.text.set("0%")
        self.percent = tk.Label(textvariable = self.text)
        self.percent.grid(column=0, row=0)
        self.progress.grid(column=1, row=0)

    def value(self, value):
        self.progress['value'] = value
        percent_value = round(value, 1)
        self.text.set(str(percent_value) + '%')


if __name__ == "__main__":
    root = tk.Tk()

    progress = ProgressBarPercent(root, orient = tk.HORIZONTAL, 
                  length = 100, mode = 'determinate') 

    progress.grid()
    progress.value(37.322)

    root.mainloop()

Solution

  • You didn't make the label a child of your class, so it becomes a child of the root window. As a general rule of thumb, all widgets inside a class that inherits from some other widget should be a child or descendant of self.

    self.percent = tk.Label(self, textvariable = self.text)
                            ^^^^^^
    

    With that, you can use pack or grid inside ProgressBarPercent, and either one in the parent, and they will be independent of each other.