Home > OS >  tkinter label inside frame of frame
tkinter label inside frame of frame

Time:09-22

I am now practicing how dynamic the frame setting can be in tkinter.

For pure frame setting, it looks perfect:

import tkinter as tk

class MyWindow: 
    def __init__(self, root):
        
        w_root = 1280
        h_root = 720
        root.title('My model')
        root.geometry(f"{w_root}x{h_root}")
        
        self.top_frame = tk.Frame(root, width=w_root, height=80, bg='grey')
        self.top_frame.grid(row=0, column=0, padx=0, pady=5)
        self.main_frame = tk.Frame(root, width=w_root, height=640, bg='blue')
        self.main_frame.grid(row=1, column=0, padx=0, pady=0) 
        self.left_frame = tk.Frame(self.main_frame, width=500, height=620, bg='red')
        self.left_frame.grid(row=0, column=0, padx=5, pady=5)       
        self.right_frame = tk.Frame(self.main_frame, width=760, height=620, bg='yellow')
        self.right_frame.grid(row=0, column=1, padx=5, pady=5)
          

root = tk.Tk()
mywin = MyWindow(root)
root.mainloop()

enter image description here

However, when I tried to put a label in left_frame (frame inside main frame), the interface became strange:

import tkinter as tk

class MyWindow: 
    def __init__(self, root):
        
        w_root = 1280
        h_root = 720
        root.title('My model')
        root.geometry(f"{w_root}x{h_root}")
        
        self.top_frame = tk.Frame(root, width=w_root, height=80, bg='grey')
        self.top_frame.grid(row=0, column=0, padx=0, pady=5)
        self.main_frame = tk.Frame(root, width=w_root, height=640, bg='blue')
        self.main_frame.grid(row=1, column=0, padx=0, pady=0) 
        self.left_frame = tk.Frame(self.main_frame, width=500, height=620, bg='red')
        self.left_frame.grid(row=0, column=0, padx=5, pady=5)       
        self.right_frame = tk.Frame(self.main_frame, width=760, height=620, bg='yellow')
        self.right_frame.grid(row=0, column=1, padx=5, pady=5)
        
        
        self.lb_currdate = tk.Label(self.left_frame, text='my lable1:')
        self.lb_currdate.config(font=('Arial', 9))
        self.lb_currdate.grid(row=0,column=0, padx=5, pady=5)
        
        self.ent_currdate = tk.Entry(self.left_frame)
        self.ent_currdate.insert(tk.END, str(0))
        self.ent_currdate.grid(row=0,column=1, padx=5, pady=5)

root = tk.Tk()
mywin = MyWindow(root)
root.mainloop() 

enter image description here

I would expect the frames look the same and the label and entry will displace on top of red frame (left frame).

I am so confused about this, could someone give me a hint which line of codes are wrong?

Thank you

#-----Update------

Based on the suggestion, I included sticky in my grid. It looks much better but still not 100% as what I expected. I try different combination of sticky, but none of them is correct:

Test1 (give left frame sticky):

self.left_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)

enter image description here

the mainframe doesn't filled enti

Test2 (give left frame and main frame both sticky):

self.main_frame.grid(row=1, column=0, padx=0, pady=0, sticky=tk.N   tk.E   tk.S   tk.W)

self.left_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)

enter image description here

left frame and right frame doesn't fill the main frame

CodePudding user response:

Making the red frame expand to fill its grid cell

The problem is that the frame automatically resizes to fit the content. To fix this, you can use the sticky keyword argument of the grid method.

self.left_frame.grid(row=0, column=0, padx=5, pady=5, sticky='NESW')

The 'NESW' stands for "north, east, south, west". If you prefer, you can write this as:

self.left_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)

You will need to do this for every frame that you want to behave like this.

You can also use different sticky values to produce different outcomes, e.g. if you just use sticky=tk.S then the frame will move to the bottom of its available space.

Removing unwanted empty space

In order to make the frames fill the space, you can use grid_rowconfigure and grid_columnconfigure with the weight keyword argument. See here for a full explaintion.

In short, you need to configure the grid to expand to fill the available space rather than manually specifying widths and heights. I have modified your code to do this. Note that the only time the height is specified in pixels is when the frame is not supposed to expand, namely for the top_frame.

import tkinter as tk


class MyWindow:
    def __init__(self, root: tk.Tk):
        w_root = 1280
        h_root = 720
        root.title('My model')
        root.geometry(f"{w_root}x{h_root}")

        self.top_frame = tk.Frame(root, height=80, bg='grey')
        self.top_frame.grid(row=0, column=0, padx=0, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)
        self.main_frame = tk.Frame(root, bg='blue')
        root.grid_rowconfigure(1, weight=1)
        root.grid_columnconfigure(0, weight=1)

        self.main_frame.grid(row=1, column=0, padx=0, pady=0, sticky=tk.N   tk.E   tk.S   tk.W)
        self.main_frame.grid_rowconfigure(0, weight=1)

        self.left_frame = tk.Frame(self.main_frame, bg='red')
        self.left_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)
        self.main_frame.grid_columnconfigure(0, weight=1)

        self.right_frame = tk.Frame(self.main_frame, bg='yellow')
        self.right_frame.grid(row=0, column=1, padx=5, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)
        self.main_frame.grid_columnconfigure(1, weight=2)

        self.lb_currdate = tk.Label(self.left_frame, text='my lable1:')
        self.lb_currdate.config(font=('Arial', 9))
        self.lb_currdate.grid(row=0, column=0, padx=5, pady=5)

        self.ent_currdate = tk.Entry(self.left_frame)
        self.ent_currdate.insert(tk.END, str(0))
        self.ent_currdate.grid(row=0, column=1, padx=5, pady=5, sticky=tk.N   tk.E   tk.S   tk.W)
        self.left_frame.grid_columnconfigure(1, weight=1)


root = tk.Tk()
mywin = MyWindow(root)
root.mainloop()

  • Related