A Frame that has 2 rows and 1 column can be weighted. From my understanding, this will set the growth from some arbitrary position to be proportional. So something like:
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=10)
# # ============ frame_header ============
self.frame_header = tk.Frame(master=self, bg='red')
self.frame_header.grid(row=0, column=0, sticky="nsew")
self.frame_header.grid_rowconfigure(0, weight=1)
self.frame_header.grid_columnconfigure(0, weight=1)
self.label1 = tk.Label(master=self.frame_header, text = 'HEADER', bg='red')
self.label1.grid(row=0, column=0, sticky="nsew")
# # ============ frame_main ============
self.frame_main = tk.Frame(master=self)
self.frame_main.grid(row=1, column=0, sticky="nsew")
self.frame_main.grid_rowconfigure(0, weight=1)
self.frame_main.grid_columnconfigure(0, weight=1)
self.label2 = tk.Label(master=self.frame_main, text = 'MAIN')
self.label2.grid(row=0, column=0, sticky="nsew")
will yield a window in which the top half and bottom half are weighted differently. But they are not actually in a 1:10 proportion. This is evident that as the window is resized, the proportion changes:
So I'm sure there's some other flag I have to set, or some other aspect of the layout manager I'm missing, but I have not been able to find anything that addresses this.
From my understanding, this will set the growth from some arbitrary position to be proportional
Not so much arbitrary, but rather initial. Grid will compute the layout based on the requested size of the widgets. If there is any unallocated space left over, the space will be allocated to each row or column proportional to its weight.
If you set the uniform option to be the same string for a group of rows or columns along with a weight, they will all be sized proportional to their weights.
This is from the official grid documentation:
The -uniform option, when a non-empty value is supplied, places the row in a uniform group with other rows that have the same value for -uniform. The space for rows belonging to a uniform group is allocated so that their sizes are always in strict proportion to their -weight values
The tcl/tk man pages have a section titled The Grid Algorithm which explains exactly how grid works.
My code is as follows:
Code
but = Button(root, text="Translate!", command= lambda : gtrans(tren.get()))
but.grid(row=2, column=2, padx=5, pady=5)
but2 = Button(root, text="Clear", command = lambda: reset())
but2.grid(row=2, column=3, padx=5, pady=5)
And my output is as follows:
This is what appears when i extend a 300x300 window
Please Help
If you follow your pastebin, you can see that both your label and entry are also in col = 2 (i.e. same as 'Translate!' button). So the issue is not a big gap between columns(the gap between Entry window and the 'Clear' button is rather small). The issue is the width of col2 is fitting your label.
What you could do:
Add columnspan = 2 to both Entry and Label (thus these elements will
span over column 2 and column 3) as lab.grid(row=0, column=2, columnspan = 2) and tren.grid(row=1, column=2, columnspan = 2)
Following this answer you could add sticky = 'E' on your
'Translate!' button to move it to the right edge of column 2, thus
reducing gap between the two buttons (I'm not sure if it would look
the best, but it depends how you want it to be)
I want to create a GUI with tkinter in python using grid-Method and grid_columnconfigure/grid_rowconfigure.
Unfortunately, this is not working inside a Frame.
How can I get this work?
from tkinter import *
master = Tk()
master.state('zoomed')
f = Frame(master, width=800, height=400)
Label1 = Label(f, text='Label 1')
Label2 = Label(f, text='Label 2')
f.grid_columnconfigure(0, weight=1)
f.grid_columnconfigure(2, weight=1)
f.grid_columnconfigure(4, weight=1)
Label1.grid(row=0, column=1)
Label2.grid(row=0, column=3)
f.pack()
master.mainloop()
ADDITIONAL QUESTION:
I got great answers, all is working fine with pack-Manager.
But how could I do this if using grid-Manager?
The grid_columnconfigure is working fine. The problem is that your frame will by default set its size to the smallest possible size to fit the labels. Since empty columns don't have a size, the frame will be just wide enough to hold the two labels.
This will be easy to visualize if you give frame a distinctive color during development. It also sometimes helps to give the frame a visual border so you can see its boundaries.
While I don't know what your ultimate goal is, you can see the spaces between the column if you have the frame fill the entire window:
f.pack(fill="both", expand=True)
If you want to use grid instead of pack, you have to do a bit more work. In short, put the frame in row 0 column 0, and give that row and column a non-zero weight so that grid will give all unused space to that row and column.
f.grid(row=0, column=0, sticky="nsew")
master.grid_rowconfigure(0, weight=1)
master.grid_columnconfigure(0, weight=1)
If you want to force the window to be a specific size, you can use the geometry method of the master window:
master.geometry("800x400")
I'm trying to set a minimum width to a column in a grid, but it is having no effect:
labelProjectId = Tkinter.Label(frame, text="Id", background='white', borderwidth=1, relief="solid")
abelProjectId.grid(row=row, column=0, sticky=("W", "E"))
labelProjectId.grid_columnconfigure(0, minsize=200) # ???
What am I doing wrong?
You are setting the minimum width for the grid inside the label. If you want to affect the column that the label is in, you must call grid_columnconfigure on its master.
I'm using tkinter to write a card game, and I'm having trouble with he grid layout manager 'sticky' configuration. I would like help fixing my code to make the frames display in the desired location. In my code and illustration below, there is a frame (b2) that contains two other (one green, b2a; and one red; b2b) frames. I would like to display frame b2 at the bottom of the parent frame (frame b). I've tried various combinations of N+S+E+W as arguments for 'sticky', for both frame b2 and the child frames b2a and b2b. However, I've been unable to make frame b2 (and more importantly b2a and b2b) appear in the desired location (the bottom image below with the correct placement was made in Illustrator).
In particular, it seems that sticky arguments in lines 27, 36 and 37 have no effect on the placement of frame b2, b2a and b2b inside of frame b.
from tkinter import *
from PIL import Image, ImageTk
def main(root):
cons = Frame(root)
cons.grid()
frameDict = setup_frames(cons)
populate_frames(frameDict)
def setup_frames(cons):
frame = {}
# Parental Frames
frame['a'] = Frame(cons, borderwidth=2, relief='groove')
frame['b'] = Frame(cons, borderwidth=2, relief='groove')
frame['c'] = Frame(cons, borderwidth=2, relief='groove')
frame['a'].grid(row=0, column=0, sticky=N+S+E+W)
frame['b'].grid(row=0, column=1, sticky=N+S+E+W)
frame['c'].grid(row=1, column=0, columnspan=2)
# Progeny 0 Frames:
frame['b1'] = Frame(frame['b'], borderwidth=2, relief='groove')
frame['b2'] = Frame(frame['b'], borderwidth=2, relief='groove')
frame['b1'].grid(row=0, column=0, sticky=N+S+E+W)
frame['b2'].grid(row=1, column=0, sticky=N+S+E+W)
# Progeny 1 Frames:
frame['b2a'] = Frame(frame['b2'], borderwidth=2, relief='groove',
background='green')
frame['b2b'] = Frame(frame['b2'], borderwidth=2, relief='groove',
background='red')
frame['b2a'].grid(row=0, column=0, sticky=S)
frame['b2b'].grid(row=0, column=1, sticky=SW)
return frame
def populate_frames(fr):
# Populating 'a' frame
aLab = Label(fr['a'], image=img[0])
aLab.grid()
# Populating b2a & b2b frames
bLab = Label(fr['b2a'], image=img[1])
bLab.grid(row=0, column=0)
bLab = Label(fr['b2b'], image=img[2])
bLab.grid(row=0, column=1)
# Populating c1 frame
cLab = Label(fr['c'], image=img[3])
cLab.grid()
if __name__ == '__main__':
root = Tk()
img = []
w = [40, 160, 80, 480]
h = [180, 60, 60, 60]
for i in range(4):
a = Image.new('RGBA', (w[i], h[i]))
b = ImageTk.PhotoImage(a)
img.append(b)
main(root)
The images below illustrate where the offending frames (green and red) are displaying (top) and where I would like them displayed (bottom).
Could someone please help me display frame b2 (and ultimately b2a and b2b) in the correct position (Edit: at the bottom of frame b, and spanning from the right side of frame a to the right side of frame c)?
Update:
I've solved both problems (vertical placement and horizontal justification of frame b2) using grid weights, as Bryan suggested. The solution to the vertical placement problem is straightforward, but I would not have predicted the solution to the horizontal justification issue.
I solved the vertical placement problem by giving weight=1 to row 0 in frame b (resulting in the upper panel of the figure below).
I solved the horizontal justification problem (wherein frames b1 and b2 were not stretching to fill frame b) by assigning weight=1 to column 0 in frame b. The frame outlines in the figure below show that frame b is already stretched from the right side of frame a to the right side of frame c. It's strange to me that giving weight to the only column in a frame would be required to allow child frames to fill horizontally. In any case, I've pasted my working code below. Lines 40 and 41 solved the issue I was having.
from tkinter import *
from PIL import Image, ImageTk
def main(root):
cons = Frame(root)
cons.grid()
frameDict = setup_frames(cons)
populate_frames(frameDict)
def setup_frames(cons):
frame = {}
# Parental Frames
frame['a'] = Frame(cons, borderwidth=2, relief='groove')
frame['b'] = Frame(cons, borderwidth=2, relief='groove')
frame['c'] = Frame(cons, borderwidth=2, relief='groove')
frame['a'].grid(row=0, column=0, sticky=N+S+E+W)
frame['b'].grid(row=0, column=1, sticky=N+S+E+W)
frame['c'].grid(row=1, column=0, columnspan=2)
# Progeny 0 Frames:
frame['b1'] = Frame(frame['b'], borderwidth=2, relief='groove')
frame['b2'] = Frame(frame['b'], borderwidth=2, relief='groove')
frame['b1'].grid(row=0, column=0, sticky=N+S+E+W)
frame['b2'].grid(row=1, column=0, sticky=N+S+E+W)
# Progeny 1 Frames:
frame['b2a'] = Frame(frame['b2'], borderwidth=2, relief='groove',
background='green')
frame['b2b'] = Frame(frame['b2'], borderwidth=2, relief='groove',
background='red')
frame['b2a'].grid(row=0, column=0, sticky=S)
frame['b2b'].grid(row=0, column=1, sticky=SW)
# Weighting
frame['b'].grid_rowconfigure(0, weight=1)
frame['b'].grid_columnconfigure(0, weight=1)
return frame
def populate_frames(fr):
# Populating 'a' frame
aLab = Label(fr['a'], image=img[0])
aLab.grid()
# Populating b2a & b2b frames
bLab = Label(fr['b2a'], image=img[1])
bLab.grid(row=0, column=0)
bLab = Label(fr['b2b'], image=img[2])
bLab.grid(row=0, column=1)
# Populating c1 frame
cLab = Label(fr['c'], image=img[3])
cLab.grid()
if __name__ == '__main__':
root = Tk()
img = []
w = [40, 160, 80, 480]
h = [180, 60, 60, 60]
for i in range(4):
a = Image.new('RGBA', (w[i], h[i]))
b = ImageTk.PhotoImage(a)
img.append(b)
main(root)
Consistent with Bryan's advice, it does seem to be a good rule of thumb to assign a weight to at least one column and one row in every container.
Here's before and after I fixed the horizontal justification problem:
Using Python 3.4, Yosemite
You must give some rows and columns a weight, so tkinter knows how to allocate extra space.
As a rule of thumb when using grid, every container using grid should give at least one row and one column weight.
What I would do is start over. Be methodical. Get the main three areas working first before tackling other problems. What is making this problem hard to solve is that nothing is behaving right, so you're trying to adjust many things at once. Focus on one area at a time, get it working just right, and then move on.
Given your diagram, pack seems like a much simpler solution than using grid for the children of the root window Using grid inside of frames inside of other frames using grid can be confusing.
It looks like frame C is a status bar of some sort that stretches across the bottom, so pack it first. Above that you have two areas - frame a is to the left and looks to be a fixed width, and frame c is to the right and takes up all of the extra space. Using pack, it would look like this:
frame['c'].pack(side="bottom", fill="x")
frame['a'].pack(side="left", fill="y")
frame['b'].pack(side="right", fill="both", expand=True)
Of course, you can get the exact same appearance with grid, but it will take a couple more lines of code since you have to give column 1 and row 1 a weight.
That should get the three main areas working just fine. Now all you have to worry about is the contents of frame B.
Your diagram shows that you want b2a and b2b at the bottom of frame b, with more widgets above it. Is that correct? If that's the case, you need to leave at least one extra row above it to fill the extra space.
The blank row with a positive weight will force all of the widgets to be moved toward the bottom of the area. They will take up only as much space as they need vertically, with the empty row with the non-zero weight taking up all the extra.
You then only have to worry about horizontal placement. It's unclear exactly what you expect, but the solution again revolves around giving columns weight. If you want both b2a and b2b to expand equally, give both columns an equal weight. If you want b2a to do all of the expanding, give only column zero a weight.