pythontkintergridframemacos-catalina

Python Tkinter: Inside packed frame, how to equally distribute grid() column widths?


I need to use a Frame widget to do this; I know I can do it without using the frame and just use a big grid to contain everything (with columnspan for the canvas etc.), but I'd like to put stuff in the frame if possible.

Quick info about my software versions:

=> OS: macOS Catalina 10.15.7
=> IDE: PyCharm CE
=> Python version: 3.12.5
=> tkinter Tcl version: 8.6 (from importing tkinter and using: print(tkinter.TclVersion))

I'm trying to implement the following:

I've tried the following, to no avail:

  1. setting a frame width of 500, equal to the width of the canvas
  2. using .pack_propagate(0) to stop the gridded child widgets (the 1 button and 2 labels) from affecting the frame's widths
  3. using the "sticky" attributes for the gridded button and labels (this wouldn't help anyway because it's more like how the widgets are aligned inside the grid space)
  4. packing the button and 2 labels into the frame instead, and use the "expand=True" attribute
  5. using frame.columnconfigure(n, weight=1) for each of the 3 columns
  6. packing the frame (which contains the button + labels widgets), and then packing the canvas
  7. doing window.update() before displaying the window to, well, update it

Like I said above, I can easily do this if I just get rid of the frame and grid everything, as follows:

So given what I'm trying to implement, what did I miss / do wrong, that prevented me from being able to expand the width of the grid so that it basically fills the entirety of the window width?

My code is below.

from tkinter import *

# check to see if we're in macOS
import platform
inMac = False   # global flag to check whether we're in macOS
if platform.system() == "Darwin":
    inMac = True
    print("Using macOS ...")
    from tkmacosx import Button


window = Tk()


frame = Frame(window, width=500)                # [NO HELP]: Setting frame attribute: width=500.
frame.pack()
#frame.grid(row=0,column=0)                     # [NO HELP]: Trying to put the frame and canvas in grid.
frame.pack_propagate(0)                         # [NO HELP]: Using Frame.pack_propagate(0) to stop child widgets
                                                #  from affecting the dimensions of the frame widget.

button = Button(frame, text="Button")
button.grid(row=0, column=0, sticky=W)          # [NO HELP]: Setting "sticky" attribute.
#button.pack(side=LEFT, fill="x", expand=True)  # [NO HELP]: Setting "expand" attribute with Button.pack().


label_1 = Label(frame, text="Whatever #1")
label_1.grid(row=0, column=1)
#label_1.pack(side=LEFT, fill="x", expand=True) # [NO HELP]: Setting "expand" attribute with Label.pack().

label_2 = Label(frame, text="Whatever #2")
label_2.grid(row=0, column=2, sticky=E)         # [NO HELP]: Setting "sticky" attribute.
#label_2.pack(side=LEFT, fill="x", expand=True) # [NO HELP]: Setting "expand" attribute with Button.pack().

frame.columnconfigure(0, weight=1)              # [NO HELP]: Setting equal weights for each column
frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1)

canvas = Canvas(window, width=500, height=500)
#canvas.grid(row=1, column=0)                   # [NO HELP]: (As above) Trying to put the frame and canvas in grid.
canvas.pack()

# [NO HELP]: Update window before we display it
#window.update()


window.mainloop()

Thank you.


Solution

  • To achieve what you want, you need to:

    Below is the modified code:

    from tkinter import *
    import platform
    
    inMac = False
    if platform.system() == "Darwin":
        inMac = True
        print("Using macOS ...")
        from tkmacosx import Button
    
    window = Tk()
    
    frame = Frame(window)
    frame.pack(fill='x')  # added fill='x'
    
    button = Button(frame, text="Button")
    button.grid(row=0, column=0, sticky=EW)
    
    label_1 = Label(frame, text="Whatever #1", bg='yellow')
    label_1.grid(row=0, column=1, sticky=EW)
    
    label_2 = Label(frame, text="Whatever #2", bg='cyan')
    label_2.grid(row=0, column=2, sticky=EW)
    
    frame.columnconfigure(0, weight=1, uniform='a') # added uniform='a'
    frame.columnconfigure(1, weight=1, uniform='a')
    frame.columnconfigure(2, weight=1, uniform='a')
    
    canvas = Canvas(window, width=500, height=500, bg='pink')
    canvas.pack(fill='both', expand=1)
    
    window.mainloop()
    

    Note that I have added sticky=EW to .grid(...) on those button and labels so that those widgets will be expanded to fill the allocated space. Also setting background color on those widgets to show the final effect.

    Output:

    enter image description here

    Note that my platform is Windows, but I think that the result will be the same on MacOS.