1
votes

I'm playing with tkinter frames layout. I got a great anwser from Bryan yestarday, unfortunetly I run into problem filling my frames. For some reason right upper frame is getting some extra space from the main frame and that breaks my layout, how can I prevent this from happening ? its OK if the label_frame expands but I don't want it to get an extra space from the main frame.

import sys
import os

import Tkinter as tk
import ttk as ttk

#
# Right Window
#
class RightUpperWindow(tk.Frame):
    def __init__(self, master=None):
        self.parent = master
        tk.Frame.__init__(self, self.parent, bg='bisque', borderwidth=0, relief="sunken")
        self.__create_layout()

    def __create_layout(self):

        self.label_frame = tk.LabelFrame(self, text="I'm a Label frame", padx=0, pady=0, borderwidth=0, width = 1)

        self.label1=tk.Label(self.label_frame, text="text1")
        self.label2=tk.Label(self.label_frame, text="text2")
        self.label3=tk.Label(self.label_frame, text="text3")

        self.entry1 = tk.Entry(self.label_frame)
        self.entry2 = tk.Entry(self.label_frame)
        self.entry3 = tk.Entry(self.label_frame)

        self.label_frame.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))

        self.label1.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.label2.grid(row=1, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.label3.grid(row=2, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))

        self.entry1.grid(row = 0, column = 1, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.entry2.grid(row = 1, column = 1, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.entry3.grid(row = 2, column = 1, sticky=(tk.N, tk.S, tk.W, tk.E))

        self.label_frame.columnconfigure(0, weight=1)
        self.label_frame.rowconfigure(0, weight=1)

#
# MainWindow
#
class MainWindow(tk.Frame):
    def __init__(self, master=None):
        self.parent = master
        tk.Frame.__init__(self, self.parent, bg='bisque', borderwidth=1, relief="sunken")
        self.__create_layout()

    def __create_layout(self):
        self.frame1 = tk.Frame(self, bg="grey")
        self.frame2 = RightUpperWindow(self) #tk.Frame(self, bg="blue")
        self.frame3 = tk.Frame(self, bg="green")
        self.frame4 = tk.Frame(self, bg="brown")
        self.frame5 = tk.Frame(self, bg="pink")

        self.frame1.grid(row=0, column=0, rowspan=4, columnspan=8, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.frame2.grid(row=0, column=8, rowspan=4, columnspan=2, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.frame3.grid(row=4, column=0, rowspan=2, columnspan=5, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.frame4.grid(row=4, column=5, rowspan=2, columnspan=5, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.frame5.grid(row=5, column=0, rowspan=1, columnspan=10, sticky=(tk.N, tk.S, tk.W, tk.E))

        for r in range(6):
            self.rowconfigure(r, weight=1)
        for c in range(10):
            self.columnconfigure(c, weight=1)

#
#   MAIN
#
def main():
    root = tk.Tk()

    root.title("Frames")
    root.geometry("550x300+525+300")

    root.configure(background="#808080")
    root.option_add("*font", ("Courier New", 9, "normal"))

    window = MainWindow(master=root)
    window.pack(side="top", fill="both", expand=True)
    root.mainloop()

if __name__ == '__main__':
    main()

enter image description here

planned layout

enter image description here

2
the second image is my planned layout - krusty

2 Answers

1
votes

The only problem is that you haven't given a weight to the row and the column that the label frame is in. You've given weights to the widgets in the label frame, but not weights to RightUpperWindow.

Add this to RightUpperWindow.__create_layout

self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)

Every time you use grid in a container, you need to give at least one row and one column in that container a weight. This needs to be done for every container that is using grid to manage its children.

Personally, if this were my code I'd use pack to put the labelframe inside of UpperRightWindow since it's the only window in that frame. With pack yo don't have to use extra lines to add weights to rows and columns. There's nothing wrong with mixing grid and pack in the same application, as long as you use them in different frames.

The above fixes the problem that the inner labelframe wasn't expanding to fill the space given to it. You also have the problem that the wrong widgets inside the label frame are expanding.

You're currently giving a weight to row and column 0 inside the labelframe, which will not give you the expected output. Since you want all of the rows to be a uniform height, give the row below the last widget a weight so that it takes up all the extra space. Also, you probably want to give column one a weight, since it makes more sense to grow and shrink the input field rather than the label.

Change this:

    self.label_frame.columnconfigure(0, weight=1)
    self.label_frame.rowconfigure(0, weight=1)

... to this:

    self.label_frame.columnconfigure(1, weight=1)
    self.label_frame.rowconfigure(3, weight=1)
-1
votes

You appear to be adding all the text/entry labels to self.label_frame, which is placed on row 0 column 8 of your main frame. I assume you want to use the 4 rows and 2 columns allocated to the upper right window for these labels and entries? If that case there is no need to use label_frame. Try something like this instead:

#
# Right Window
#
class RightUpperWindow(tk.Frame):
    def __init__(self, master=None):
        self.parent = master
        tk.Frame.__init__(self, self.parent, bg='bisque', borderwidth=0, relief="sunken")
        self.__create_layout()

    def __create_layout(self):

        # self.label_frame = tk.LabelFrame(self, text="I'm a Label frame", padx=0, pady=0, borderwidth=0, width = 1)
        self.label0=tk.Label(self, text="header")
        self.label1=tk.Label(self, text="text1")
        self.label2=tk.Label(self, text="text2")
        self.label3=tk.Label(self, text="text3")

        self.entry1 = tk.Entry(self)
        self.entry2 = tk.Entry(self)
        self.entry3 = tk.Entry(self)

        # self.label_frame.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.label0.grid(row=0, column=0, columnspan=2, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.label1.grid(row=1, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.label2.grid(row=2, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.label3.grid(row=3, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))

        self.entry1.grid(row = 1, column = 1, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.entry2.grid(row = 2, column = 1, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.entry3.grid(row = 3, column = 1, sticky=(tk.N, tk.S, tk.W, tk.E))

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)