Assigning a columnspan (other than 1) to a child object appears to negate the effects of uniform=1 and grid_propagate(False). Here is a simple example of what I mean (click the text to toggle back and forth and observe the change).
import tkinter as tk
class TestInterface:
def __init__(self, master):
self.master = master
self.master.title("Interface Template")
self.master.configure(bg='#000000', relief=tk.RIDGE, borderwidth=16)
self.master.attributes('-fullscreen', True)
self.demonstration_frame = tk.Frame()
self.dummy_frame = tk.Frame()
self.button = tk.Button()
self.button1()
def button1(self):
self.remake_test_frame()
self.button = tk.Button(self.demonstration_frame, text="LONG PHRASE MODIFYING THE GRID STRUCTURE", bg='#111111',
relief=tk.FLAT, fg="#FFFFFF", font=('Courier', 12), anchor='center', borderwidth=6,
command=lambda: self.button2())
self.button.grid(row=2, column=3, columnspan=2, sticky='nsew')
def button2(self):
self.remake_test_frame()
self.button = tk.Button(self.demonstration_frame, text="LONG PHRASE BEING CUT OFF AS INTENDED", bg='#111111',
relief=tk.FLAT, fg="#FFFFFF", font=('Courier', 12), anchor='center', borderwidth=6,
command=lambda: self.button1())
self.button.grid(row=2, column=3, sticky='nsew')
def remake_test_frame(self):
self.demonstration_frame.destroy()
self.demonstration_frame = tk.Frame(master=self.master, relief=tk.FLAT, borderwidth=4, bg='blue')
self.demonstration_frame.pack(expand=True, fill="both")
self.demonstration_frame.grid_propagate(False)
for k in range(4):
self.demonstration_frame.grid_rowconfigure(k, weight=1, uniform=1)
for i in range(6):
self.demonstration_frame.grid_columnconfigure(i, weight=1, uniform=1)
for j in range(4):
self.dummy_frame = tk.Frame(self.demonstration_frame, relief=tk.RIDGE, borderwidth=1,
bg='#' str(int(j / 2)) str(int(j / 2)) str(int(j / 2))
str(int(i / 2)) str(int(i / 2)) str(int(i / 2)))
self.dummy_frame.grid(row=j, column=i, sticky='nsew')
root = tk.Tk()
my_gui = TestInterface(root)
root.mainloop()
I have demonstration_frame being re-formed from scratch with each button click, so we know that frame is being created in the same way each time. The dummy_frames are just to make clear what is happening. The only difference between self.button1() and self.button2() is the removal of "columnspan=2."
I want these grid lines locked in place (I'm fine with text being invisible/off-frame). Can anyone explain why columnspan is changing the behavior of grid_propagate() here?
edit: here is the code without the demonstration_frame.destroy method. It behaves the exact same way.
import tkinter as tk
class TestInterface:
def __init__(self, master):
self.master = master
self.master.title("Interface Template")
self.master.configure(bg='#000000', relief=tk.RIDGE, borderwidth=16)
self.master.attributes('-fullscreen', True)
self.demonstration_frame = tk.Frame(master=self.master, relief=tk.FLAT, borderwidth=4, bg='blue')
self.demonstration_frame.pack(expand=True, fill="both")
self.demonstration_frame.grid_propagate(False)
for k in range(4):
self.demonstration_frame.grid_rowconfigure(k, weight=1, uniform=1)
for i in range(6):
self.demonstration_frame.grid_columnconfigure(i, weight=1, uniform=1)
for j in range(4):
self.dummy_frame = tk.Frame(self.demonstration_frame, relief=tk.RIDGE, borderwidth=1,
bg='#' str(int(j / 2)) str(int(j / 2)) str(int(j / 2))
str(int(i / 2)) str(int(i / 2)) str(int(i / 2)))
self.dummy_frame.grid(row=j, column=i, sticky='nsew')
self.dummy_frame = tk.Frame()
self.button = tk.Button()
self.button1()
def button1(self):
self.button = tk.Button(self.demonstration_frame, text="LONG PHRASE MODIFYING THE GRID STRUCTURE", bg='#111111',
relief=tk.FLAT, fg="#FFFFFF", font=('Courier', 12), anchor='center', borderwidth=6,
command=lambda: self.button2())
self.button.grid(row=2, column=3, columnspan=2, sticky='nsew')
def button2(self):
self.button.destroy()
self.button = tk.Button(self.demonstration_frame, text="LONG PHRASE BEING CUT OFF AS INTENDED", bg='#111111',
relief=tk.FLAT, fg="#FFFFFF", font=('Courier', 12), anchor='center', borderwidth=6,
command=lambda: self.button1())
self.button.grid(row=2, column=3, sticky='nsew')
root = tk.Tk()
my_gui = TestInterface(root)
root.mainloop()
CodePudding user response:
Can anyone explain why columnspan is changing the behavior of grid_propagate() here?
In this example, columnspan
is not changing the behavior of grid_propagate
. Turning off grid propagation only tells the parent not to grow or shrink based on the children. The size of the parent isn't changing when you use columnspan
- the frame stays the size that it was. What changes is the size of the inner columns, which has nothing to do with geometry propagation.
I've never seen this behavior before, and it does seem unintuitive. However, I think it's working as designed.
The canonical documentation for the grid algorithm starts with the following:
"To compute the minimum size of a layout, the grid geometry manager first looks at all content whose columnspan and rowspan values are one, and computes the nominal size of each row or column to be either the minsize for that row or column, or the sum of the padding plus the size of the largest content, whichever is greater. After that the rows or columns in each uniform group adapt to each other. "
At this point in the algorithm the rows and columns in your example should all be the same width and height. So far, so good.
The documentation then addresses what happens when widgets span two or more rows or columns:
"Then the content whose row-spans or column-spans are greater than one are examined. If a group of rows or columns need to be increased in size in order to accommodate these content, then extra space is added to each row or column in the group according to its weight. For each group whose weights are all zero, the additional space is apportioned equally."
This seems to describe exactly what you are seeing: extra space is added to columns 3 and 4 so that the button will fit.
My guess is that you can put the button in a frame that has no width and height, and turn geometry propagation off in that frame. Make sure you use options that cause the button to fill the frame. You can then put that frame where you are currently putting the button, spanning two columns. Since the frame will have a requested size of 1x1 it will not cause the columns to grow.