pythontkinterttk

Python tkinter - grid configuration


So i just wanted to understand why tkinter is not sticking the sizegrip to the bottom right (SE) of the root window if I dont't call .columnconfiguration() and .rowconfiguration() methods on the root. It's behaving in weird ways and I don't understand why.

When I write:

# ttk app
class Application(ttk.Frame):
    '''
    Main ttk app, inherited from ttk.Frame.
    '''
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        folderSelector_Frame = ttk.Frame(self)
        self.folderSelector_Treeview = ttk.Treeview(folderSelector_Frame)
        
        outputText_Frame = ttk.Frame(self)
        self.outputText = tk.StringVar(outputText_Frame)
        self.outputText_Label = ttk.Label(outputText_Frame, textvariable= self.outputText)
        
        
        inputParent_Frame = ttk.Frame(self) 
        
        
        
        # Layout
        self.folderSelector_Treeview.pack()
        self.outputText_Label.pack()
        
        folderSelector_Frame.grid(column= 0, row=0)
        outputText_Frame.grid(column= 2, row= 0)
        ttk.Separator(self, orient= "vertical").grid(column= 1, row= 0, sticky= tk.NS)
        inputParent_Frame.grid(column= 4, row= 0)
        ttk.Separator(self, orient= "vertical").grid(column=3, row=0, sticky= tk.NS)
    

def main() -> None:
    '''
    Main, creates tk.Tk() named root and calls instance of Application with root as master, packs Application and runs mainloop on root.
    '''
    root = tk.Tk()
    root.resizable(width= True, height= True)
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)
    
    Application(master= root).grid(column= 0, row= 0)
    ttk.Sizegrip().grid(row= 6, sticky= tk.SE)
    
    
    root.mainloop()
    
if __name__ == "__main__":
    main()

It works but if I were to write:

def main() -> None:
    '''
    Main, creates tk.Tk() named root and calls instance of Application with root as master, packs Application and runs mainloop on root.
    '''
    root = tk.Tk()
    root.resizable(width= True, height= True)
    
    Application(master= root).grid(column= 0, row= 0)
    ttk.Sizegrip().grid(row= 6, sticky= tk.SE)
    
    
    root.mainloop()

The sizegrip gets stuck on the bottom right of the Application frame. Even the resizing logic changes and the Application stays on the top left, while with the previous version it remained in the center

Even if I were to use pack instead of grid it's still giving problems:

def main() -> None:
    '''
    Main, creates tk.Tk() named root and calls instance of Application with root as master, packs Application and runs mainloop on root.
    '''
    root = tk.Tk()
    root.resizable(width= True, height= True)

    Application(master= root).pack()
    ttk.Sizegrip().pack(anchor= tk.SE)
    
    
    root.mainloop()

In this case, the sizegrip stays at the same y (?) coordinate but sticks to the right border of root, and the replacement logic changes accordingly: Application is centered along the x axis but not the y axis, even though I put tk.SE parameter and not just tk.E.


Solution

  • It is because by default rows and columns are as small as possible, being just large enough to hold their contents. All extra space in the UI goes unused.

    The weight option is used to tell grid how to allocate extra, unused space. By default the weight of every row and every column is 0 (zero), meaning no rows or columns are allocated any of the available extra space. When you add a positive weight to just one row and just one column, all extra space is allocated to that row/column.

    In the case of placing a size grip, place is usually the best tool for the job since it allows you to place it in the bottom right corner independently of any other widgets. It allows you to put the south-east corner of the grip at the bottom right corner using relative positioning, as in the following example:

    ttk.Sizegrip(root).place(relx=1.0, rely=1.0, anchor="se")
    

    I would also recommend using pack if your UI is designed such that everything is in a single frame, and you want that single frame to fill the window. Using pack lets you avoid having to configure weights.

    Here is how I would write your main function:

    app = Application(master=root)
    grip = ttk.Sizegrip(master=root)
    
    app.pack(fill="both", expand=True)
    grip.place(relx=1.0, rely=1.0, anchor="se")