Tkinter labels not filling up in the Y direction after using pack even though fill=tk.Y was added

Question:

I have been looking at various sources but to no avail.

In my tkinter window, I have running Labels which start with “start” to 1 and all the way to 100. I have two problems:

  1. My labels are not stretching out in the Y direction even though fill=tk.Y is called (for self.firstlabel.pack and x.pack), as evidenced by the green background. Why is this happening?

  2. I’ve also tried to get the canvas height by first calling self.update() and then printing out the canvas height using print(self.canvas.winfo_height()). However the canvas height is still 1. Why is this the case?

Thank you all in advance for your answers!

import tkinter as tk

class Test(tk.Tk):

    def __init__(self, tasks=None):
        super().__init__()

        self.title("Test")

        # setting up container
        container = tk.Frame(self, background="bisque")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        container.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.E, tk.W))

        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=3)
        container.grid_rowconfigure(1, weight=1)

        # two frames in container, container1 for labels, container2 for textbox
        self.container1 = tk.Frame(container, background="yellow")
        self.container2 = tk.Frame(container, background="blue")
        self.container1.grid(row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        self.container2.grid(row=1, sticky=(tk.N, tk.S, tk.E, tk.W))

        self.canvas = tk.Canvas(self.container1, borderwidth=0, background="green")
        self.frameinsidecanvas = tk.Frame(self.canvas, background="pink")
        self.canvas.pack(fill="both", expand=True)
        self.frameinsidecanvas.pack(fill="both", expand=True)

        self.update()
        print(self.canvas.winfo_height())

        # setup scrollbar
        self.horizontalscrollbar = tk.Scrollbar(self.container1, orient="horizontal", command=self.canvas.xview)
        self.canvas.configure(xscrollcommand=self.horizontalscrollbar.set)
        self.horizontalscrollbar.pack(side="bottom", fill="x")

        self.canvas.create_window((0, 100), window=self.frameinsidecanvas, anchor="w")

        self.textbox = tk.Text(self.container2, height=1)
        self.textbox.pack(fill="both", expand=True)

        # creating the instructional label
        self.firstlabel = tk.Label(self.frameinsidecanvas, text="Start")
        # self.tasks.append(self.firstlabel)

        self.firstlabel.pack(side="left", fill=tk.Y, expand=True)

        # showing the labels
        for labels in range(0,100):
            x = tk.Label(self.frameinsidecanvas, text=str(labels))
            x.pack(side=tk.LEFT, fill=tk.Y, expand=True)

        self.bind("<Configure>", self.on_frame_configure)

    def on_frame_configure(self, event=None):
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    test = Test()
    test.wm_geometry("1100x500")
    test.mainloop()

Asked By: miniarcher

||

Answers:

The problem is that at the start of the program the canvas height is equal to 1. After that the tkinter window is rendered it changes the value.

You can simply bind a canvas listner to <Configure> for get when the height changes and after modify the inner fram of consequence.

import tkinter as tk
# You want to display the labels in column or that each label had the height of the canvas?
class Test(tk.Tk):

    def __init__(self, tasks=None):
        super().__init__()
        self.canvas_width = None

        self.title("Test")

        # setting up container
        container = tk.Frame(self, background="bisque")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        container.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.E, tk.W))

        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=3)
        container.grid_rowconfigure(1, weight=1)

        # two frames in container, container1 for labels, container2 for textbox
        self.container1 = tk.Frame(container, background="yellow")
        self.container2 = tk.Frame(container, background="blue")
        self.container1.grid(row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        self.container2.grid(row=1, sticky=(tk.N, tk.S, tk.E, tk.W))

        self.canvas = tk.Canvas(self.container1, borderwidth=0, background="black")

        self.frameinsidecanvas = tk.Frame(self.canvas, background="pink")
        self.canvas.pack(fill="both", expand=True)
        self.frameinsidecanvas.pack(fill="both", expand=True)

        # setup scrollbar
        self.horizontalscrollbar = tk.Scrollbar(self.container1, orient="horizontal", command=self.canvas.xview)
        self.canvas.configure(xscrollcommand=self.horizontalscrollbar.set)
        self.horizontalscrollbar.pack(side="bottom", fill="x")

        self.canvas.create_window((0, 100), window=self.frameinsidecanvas, anchor="w")

        self.textbox = tk.Text(self.container2, height=1)
        self.textbox.pack(fill="both", expand=True)

        # creating the instructional label
        self.firstlabel = tk.Label(self.frameinsidecanvas, text="start")
        # self.tasks.append(self.firstlabel)

        self.firstlabel.pack(side="left", fill=tk.Y)

        # showing the labels
        for label_index in range(0, 10):
            x = tk.Label(self.frameinsidecanvas, text=label_index)
            x.pack(side=tk.LEFT, fill=tk.Y, expand=True)

        self.canvas.bind("<Configure>", self.update_width)

    def update_width(self, e):
        self.canvas_width = self.canvas.winfo_width()
        self.canvas_height = self.canvas.winfo_height()
        self.firstlabel.configure(height=self.canvas_height)
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    test = Test()
    test.wm_geometry("1100x500")
    test.mainloop()
Answered By: Mat.C

For the first question,

If you want to fill the label widget, use firstlabel.pack(fill = 'x')

if you want to align the text on the left side, use firstlabel = tk.Label(frameinsidecanvas, text="Start", anchor = 'w') I hope you got the idea.

The below code will align the text on the left side and fill the label widget.

self.firstlabel = tk.Label(self.frameinsidecanvas, text="Start", anchor = 'w')
self.firstlabel.pack(fill=tk.Y, expand=True)
Answered By: Vasigaran_ The Boss
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.