Orient and Organize Tkinter frames - python

I would like to know how to create frames that align to grid and fill space I dictate. I am having a hard time grasping frame orientation within a window. I can make all the frames, but if I pack, they are all on left or in a line/on right. I played with that and decided on grid(). I set the window geometry and then use grid for frames. However, my frames all collapse down to the top left or my initial frame fills the whole space and the other two squeeze in around the edges. I tried using window geometry of 1024 and 768, then allotting width and height for my first frame to be 512 and 384. Then setting the next two to have width 512 and height of 192. I also saw in other articles that weight is important and tried iterations of code to alter that, but was unsuccessful. Rowspan and columnspan helped me get the background colors to appear so that I could visualize the space being occupied by each.
Anyway, code is below:
class twinsplay:
def __init__(self):
#Window
self.window = Tk()
self.window.geometry('1024x768')
self.window.grid_rowconfigure(1, weight=1)
self.window.grid_columnconfigure(1, weight=1)
#window title
self.window.title('Live Feed')
#frames and labels
self.frame_left = Frame(self.window, background='magenta')
self.frame_left.grid(row=0, column=0, padx=5, pady=5, rowspan=3, columnspan=3, sticky=NSEW)
self.label_left = Label(self.frame_left, text = 'Weather Data', justify=LEFT)
self.label_left.grid(row=0,column=0, sticky=NSEW)
self.frame_tr = Frame(self.window, background='green')
self.frame_tr.grid(row=0, column=3, padx=5, pady=5, rowspan=3, columnspan=2, sticky=NSEW)
self.label_tr = Label(self.frame_tr, text = 'Solar Data', justify = RIGHT)
self.label_tr.grid(row=0, column=512, sticky=NSEW)
self.frame_br = Frame(self.window, background='yellow')
self.frame_br.grid(padx=5, pady=5, rowspan=2, columnspan=2, sticky=NSEW)
self.label_br = Label(self.frame_br, text = 'News', justify = RIGHT)
self.label_br.grid(row=0, column=512, sticky=NSEW)
#main
self.window.mainloop()
```

I don't know if I understand your problem.
Your frames use full size inside window but elements inside frames are collapsed. You may need to use grid_rowconfigure/grid_columnconfigure also with frame_left, frame_tr, frame_br to resize elements in grid inside frames.
I move elements to rows an columns 0 because empty rows/columns have no size and there is no sense to put in column 512
from tkinter import *
class twinsplay:
def __init__(self):
self.window = Tk()
self.window.geometry('1024x768')
self.window.grid_rowconfigure(0, weight=1)
self.window.grid_columnconfigure(0, weight=1)
#window title
self.window.title('Live Feed')
#frames and labels
self.frame_left = Frame(self.window, background='magenta')
self.frame_left.grid(row=0, column=0, padx=5, pady=5, sticky=NSEW)
self.label_left = Label(self.frame_left, text = 'Weather Data', justify=LEFT, bg='red')
self.label_left.grid(row=0,column=0, sticky=NSEW)
self.frame_left.grid_rowconfigure(0, weight=1)
self.frame_left.grid_columnconfigure(0, weight=1)
# ---
self.frame_tr = Frame(self.window, background='green')
self.frame_tr.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
self.label_tr = Label(self.frame_tr, text = 'Solar Data', justify = RIGHT, bg='green')
self.label_tr.grid(row=0, column=0, sticky=NSEW)
self.frame_tr.grid_rowconfigure(0, weight=1)
self.frame_tr.grid_columnconfigure(0, weight=1)
# ---
self.frame_br = Frame(self.window, background='yellow')
self.frame_br.grid(row=1, column=0, padx=5, pady=5, columnspan=2, sticky=NSEW)
self.label_br = Label(self.frame_br, text = 'News', justify = RIGHT, bg='yellow')
self.label_br.grid(row=0, column=0, sticky=NSEW)
self.frame_br.grid_rowconfigure(0, weight=1)
self.frame_br.grid_columnconfigure(0, weight=1)
#main
self.window.mainloop()
twinsplay()
But if you try to do something different then maybe you have to use grid_rowconfigure/grid_columnconfigure with other rows/columns - you can use it many times with different rows/columns.
EDIT:
from tkinter import *
class twinsplay:
def __init__(self):
self.window = Tk()
self.window.geometry('1024x768')
# left and right column will use the same size
self.window.grid_columnconfigure(0, weight=1)
self.window.grid_columnconfigure(1, weight=1)
# top and bottom rows will use the same size
self.window.grid_rowconfigure(0, weight=1)
self.window.grid_rowconfigure(1, weight=1)
#window title
self.window.title('Live Feed')
#frames and labels
# frame will use 2 rows
self.frame_left = Frame(self.window, background='magenta')
self.frame_left.grid(row=0, column=0, padx=5, pady=5, sticky=NSEW, rowspan=2)
self.label_left = Label(self.frame_left, text = 'Weather Data', justify=LEFT, bg='red')
self.label_left.grid(row=0,column=0, sticky=NSEW)
self.frame_left.grid_rowconfigure(0, weight=1)
self.frame_left.grid_columnconfigure(0, weight=1)
# ---
self.frame_tr = Frame(self.window, background='green')
self.frame_tr.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
self.label_tr = Label(self.frame_tr, text = 'Solar Data', justify = RIGHT, bg='green')
self.label_tr.grid(row=0, column=0, sticky=NSEW)
self.frame_tr.grid_rowconfigure(0, weight=1)
self.frame_tr.grid_columnconfigure(0, weight=1)
# ---
self.frame_br = Frame(self.window, background='yellow')
self.frame_br.grid(row=1, column=1, padx=5, pady=5, columnspan=2, sticky=NSEW)
self.label_br = Label(self.frame_br, text = 'News', justify = RIGHT, bg='yellow')
self.label_br.grid(row=0, column=0, sticky=NSEW)
self.frame_br.grid_rowconfigure(0, weight=1)
self.frame_br.grid_columnconfigure(0, weight=1)
#main
self.window.mainloop()
twinsplay()

Related

How can I center a middle column in tkinter

My problem is: The output should show 2 side bars (column 0 and 2) with content Labels and Entrys and one central Window(column 1) much bigger than the other side bars in the middle. But the middle column always appears on the right side and as a very little frame.
Pls help.
My code and a picture:
import tkinter as tk, tkinter.ttk as ttk
root = tk.Tk()
root.title("THE FRIDGER")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(2, weight=1)
#prepared data
dflt = dict(fg="white", bg="black")
pads = dict(pady=4, padx=4)
#header frame
header = tk.Frame(root, bg="black")
header.grid(row=0, column=0, columnspan=3, sticky="nsew")
for i in range(2):
header.grid_columnconfigure(i, weight=1)
#header labels
tk.Label(header, text="Fridge", **dflt).grid(column=0, row=0, **pads)
tk.Label(header, text="Recipes", **dflt).grid(column=1, row=0, **pads)
#separator
s = ttk.Style()
s.configure('custom.TSeparator', background='blue')
ttk.Separator(root, style='custom.TSeparator').grid(row=1, column=0, columnspan=3, sticky="ew")
#left side content
l_content = tk.Frame(root, bg="black")
l_content.grid(row=2, column=0, sticky="nsew")
tk.Label(l_content, text="Content:", **dflt).grid(column=0, row=0, sticky=tk.W)
l_query = tk.Entry(l_content, width=36, relief=tk.FLAT, bg = "white", fg = "black")
l_query.grid(column=0, row=1, sticky=tk.W)
#right side content
r_content = tk.Frame(root, bg="black")
r_content.grid(row=2, column=2, sticky="nsew")
tk.Label(r_content, text="Content:", **dflt).grid(column=0, row=2, sticky=tk.W)
r_query = tk.Entry(r_content, width=36, relief=tk.FLAT, bg = "white", fg = "black")
r_query.grid(column=0, row=3, sticky=tk.W)
#middle content
m_content = tk.Frame(root, bg="white")
m_content.grid(row=2, column=1, sticky="nsew")
tk.Label(m_content, text="This should appear in the middle", **dflt).grid(column=0, row=2, sticky=tk.W)
m_content.grid_columnconfigure(1, weight = 1)
root.mainloop()
The reason the left column is so large is that you are giving it a weight of 1. If you want the center column to take up all of the extra space, you need to give it a positive weight instead of giving the weight to column 0.
root.grid_columnconfigure(1, weight=1)
You set weight=1 on wrong column:
root.grid_columnconfigure(0, weight=1) should be root.grid_columnconfigure(1, weight=1)
m_content.grid_columnconfigure(1, weight=1) should be m_content.grid_columnconfigure(0, weight=1)
And remove sticky option from:
tk.Label(m_content, text="This should appear in the middle", **dflt).grid(column=0, row=2, sticky=tk.W)

tkinter Frame Layout with grid and pack

I have a layout with Frame and pack some widwets inside. This works so fare. But for the treeview widget it doesn't work and gives a strange error:
Display Names in the Treeview doesn't work with pack tkinter.TclError:
cannot use geometry manager pack inside . which already has slaves
managed by grid
Need help from experienced tkinter user.
Here my layout:
here, if I try the same with a treeview instead of a label widget:
here is my program:
import tkinter as tk
from tkinter import ttk
# Main App
win = tk.Tk()
win.title('Layout Test')
win.geometry('1200x720+300+300')
win.resizable(True, True)
# Frame Design
top_frame = tk.Frame(win, background="#FFF0C1", bd=1, relief="sunken")
left_frame = tk.Frame(win, background="#D2E2FB", bd=1, relief="sunken")
center_frame = tk.Frame(win, background="#CCE4CA", bd=1, relief="sunken")
right_frame = tk.Frame(win, background ='lightblue', bd=1, relief='sunken')
bottom_frame = tk.Frame(win, background="#F5C2C1", bd=1, relief="sunken")
top_frame.grid(row=0, column=0, columnspan=3, sticky="nsew", padx=2, pady=2)
left_frame.grid(row=1, column=0, sticky="nsew", padx=2, pady=2)
center_frame.grid(row=1, column=1, sticky="nsew", padx=2, pady=2)
right_frame.grid(row=1, column=2, sticky="nsew", padx=2, pady=2)
bottom_frame.grid(row=3, column=0, columnspan=3, sticky="nsew", padx=2, pady=2)
win.grid_rowconfigure(0, weight=6)
win.grid_rowconfigure(1, weight=40)
win.grid_rowconfigure(3, weight=1)
win.grid_columnconfigure(0, weight=1)
win.grid_columnconfigure(1, weight=2)
win.grid_columnconfigure(2, weight=4)
# Display Names in the Treeview doesn't work with pack
# tkinter.TclError: cannot use geometry manager pack inside .
# which already has slaves managed by grid
treeview = ttk.Treeview(win)
treeview.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
treeview.insert('center_frame','0','item1', text = 'First item',tag='T' )
treeview.insert('center_frame','1','item2', text = 'Second item',tag='T' )
treeview.insert('center_frame','2','item3', text = 'Third item',tag='T' )
treeview.insert('center_frame','3','item4', text = 'Forth item',tag='T' )
treeview.insert('center_frame','end','item5', text = 'Five item',tag='T' )
treeview.insert('item1','end','item6', text = 'Sechster Text',tag='T' )
treeview.tag_configure('T', font=('Calibre', 15))
"""
# Test works well with pack
MyLabel = tk.Label(center_frame,text="Label inside Frame1")
MyLabel.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
"""
# Program here
# Status Bar at bottom_frame works well with pack
statustext = tk.StringVar()
statustext.set(' ... choose your avm_xml file') # will be changed from file dialoge
status = ttk.Label(bottom_frame, textvariable=statustext, borderwidth='25', relief=tk.SUNKEN, anchor=tk.W)
status.pack(side=tk.BOTTOM, fill=tk.X) #fill='both', expand=False, padx=8, pady=8
win.mainloop()
treeview has win as master, so when you try to pack it you get an error since you used grid for the other widgets in win. This is because the layout managers pack and grid cannot be used simultaneously in the same master widget.
On the other hand, your test label's master is center_frame, so you can pack it inside. If you change your treeview's master to center_frame, you will be able to pack it like the label.
import tkinter as tk
from tkinter import ttk
# Main App
win = tk.Tk()
win.title('Layout Test')
win.geometry('1200x720+300+300')
win.resizable(True, True)
# Frame Design
top_frame = tk.Frame(win, background="#FFF0C1", bd=1, relief="sunken")
left_frame = tk.Frame(win, background="#D2E2FB", bd=1, relief="sunken")
center_frame = tk.Frame(win, background="#CCE4CA", bd=1, relief="sunken")
right_frame = tk.Frame(win, background ='lightblue', bd=1, relief='sunken')
bottom_frame = tk.Frame(win, background="#F5C2C1", bd=1, relief="sunken")
top_frame.grid(row=0, column=0, columnspan=3, sticky="nsew", padx=2, pady=2)
left_frame.grid(row=1, column=0, sticky="nsew", padx=2, pady=2)
center_frame.grid(row=1, column=1, sticky="nsew", padx=2, pady=2)
right_frame.grid(row=1, column=2, sticky="nsew", padx=2, pady=2)
bottom_frame.grid(row=3, column=0, columnspan=3, sticky="nsew", padx=2, pady=2)
win.grid_rowconfigure(0, weight=6)
win.grid_rowconfigure(1, weight=40)
win.grid_rowconfigure(3, weight=1)
win.grid_columnconfigure(0, weight=1)
win.grid_columnconfigure(1, weight=2)
win.grid_columnconfigure(2, weight=4)
treeview = ttk.Treeview(center_frame) # <-- changed master from win to center_frame
treeview.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) # <-- pack works now
# Program here
# Status Bar at bottom_frame works well with pack
statustext = tk.StringVar()
statustext.set(' ... choose your avm_xml file') # will be changed from file dialoge
status = ttk.Label(bottom_frame, textvariable=statustext, borderwidth='25', relief=tk.SUNKEN, anchor=tk.W)
status.pack(side=tk.BOTTOM, fill=tk.X) #fill='both', expand=False, padx=8, pady=8
win.mainloop()
As far as I am concerned, if you change treeview.pack() to treeview.grid(sticky=W)etc it might work. You can't have both pack and grid in the same widget.

Tkinter canvas & scrollbar with grid

I have a canvas in a frame
photoFrame = Frame(centerFrame, width=250, height=190, bg="#EBEBEB")
photoFrame.grid(row=0, column=1, sticky="nsew")
photoCanvas = Canvas(photoFrame, bg="#EBEBEB")
photoCanvas.grid(row=0, column=0, sticky="nsew")
and I try to put a scrollbar to my canvas with this
photoScroll = Scrollbar(photoFrame, orient=VERTICAL)
photoScroll.config(command=photoCanvas.yview)
photoCanvas.config(yscrollcommand=photoScroll.set)
photoScroll.grid(row=0, column=1, sticky="ns")
The scrollbar appears but it's disabled. Can you help me please ?
Sorry for my bad english.
In a for loop I add lots of Image button with this code
element = Button(photoCanvas, image = listPhotos[i], borderwidth=0, height = 200, width = 200, bg="#EBEBEB")
element.grid(row=rowPhoto, column=columnPhoto, padx=5, pady=5, sticky="nsew")
Finnally I have this
root = Tk()
photoFrame = Frame(root, width=250, height=190, bg="#EBEBEB")
photoCanvas = Canvas(photoFrame, bg="#EBEBEB")
photoCanvas.grid(row=0, column=0, sticky="nsew")
for i in range(0, len(listPhotos), 1):
element = Button(photoCanvas, image = listPhotos[i], borderwidth=0, height = 200, width = 200, bg="#EBEBEB")
element.grid(row=rowPhoto, column=columnPhoto, padx=5, pady=5, sticky="nsew")
photoScroll=Scrollbar(photoFrame,orient=VERTICAL)
photoScroll.config(command=photoCanvas.yview)
photoCanvas.config(yscrollcommand=photoScroll.set)
photoScroll.grid(row=0, column=1, sticky="ns")
in my app, the purple rectangle is the next frame and I need a vertical scrollbar
Say if you have some questions
One way to scroll a group of widgets is to put them (with grid of pack) inside a frame and put this frame inside a canvas.
The two key elements (besides connecting the scrollbar to the canvas) for the scrolling to work are:
Use canvas.create_window(x, y, window=frame) to put the frame inside the canvas so that it is treated like a canvas item.
Update the canvas scrollregion each time the size of the frame changes (for instance after adding a new widget) with canvas.configure(scrollregion=canvas.bbox('all')).
Here is an adaptation of the code of the question Python Tkinter scrollbar for frame, but using the widgets name from the OP's question and grid instead of pack:
import tkinter as tk
def update_scrollregion(event):
photoCanvas.configure(scrollregion=photoCanvas.bbox("all"))
root = tk.Tk()
photoFrame = tk.Frame(root, width=250, height=190, bg="#EBEBEB")
photoFrame.grid()
photoFrame.rowconfigure(0, weight=1)
photoFrame.columnconfigure(0, weight=1)
photoCanvas = tk.Canvas(photoFrame, bg="#EBEBEB")
photoCanvas.grid(row=0, column=0, sticky="nsew")
canvasFrame = tk.Frame(photoCanvas, bg="#EBEBEB")
photoCanvas.create_window(0, 0, window=canvasFrame, anchor='nw')
for i in range(10):
element = tk.Button(canvasFrame, text='Button %i' % i, borderwidth=0, bg="#EBEBEB")
element.grid(padx=5, pady=5, sticky="nsew")
photoScroll = tk.Scrollbar(photoFrame, orient=tk.VERTICAL)
photoScroll.config(command=photoCanvas.yview)
photoCanvas.config(yscrollcommand=photoScroll.set)
photoScroll.grid(row=0, column=1, sticky="ns")
canvasFrame.bind("<Configure>", update_scrollregion)
root.mainloop()

Python Tkinter grid spacing of widgets and LablelFrames not right

I am designing a simple GUI in Python 2.7 Tkinter, but I can't get things to spread out as I want them. I have managed to get my various widgets roughly where I want them, however I can't seem to force spacing out and things are a little bunched up.
I have also tried to draw 3 LabelFrames to separate the window out, but widgets seem to fall over the LabelFrames. I am wondering how I can space this out a little better. The grid system seems to allow things to bunch up and ignores blank rows and columns as far as I can see.
from Tkinter import *
import Tkinter, Tkconstants, tkFileDialog, tkMessageBox
class FileZap():
def __init__(self, root):
root.title("TestGUI")
root.geometry("860x450")
self.topFrame = LabelFrame(root, text="Top Area")
self.topFrame.grid(row=1, column=1, rowspan=6, columnspan=7, padx=5, pady = 5, sticky="NSEW")
self.listbox1 = Listbox(root, width=50, selectmode="multiple")
self.listbox1.grid(row=3, column=2)
self.scrollbar = Scrollbar(orient=VERTICAL, command=self.listbox1.yview)
self.listbox1.config(yscrollcommand=self.scrollbar.set)
self.scrollbar.grid(row=3, column=3, sticky="ns")
self.listbox2 = Listbox(root, width=50)
self.listbox2.grid(row=3, column=4)
self.selectLabel = Label(root, text="Select a folder: ")
self.selectLabel.grid(row=3, column=1)
self.user1 = Entry(root, width="50")
self.user1.grid(row=2, column=2)
self.browse = Button(root, text="Browse")
self.browse.grid(row=2, column=3)
self.addItems = Button(root, text="Add to Selection")
self.addItems.grid(row=4, column=2)
self.clearItems = Button(root, text="Clear Selection")
self.clearItems.grid(row=4, column=4)
self.leftFrame = LabelFrame(root, text="Left Area")
self.leftFrame.grid(row=5, column=1, rowspan=6, columnspan=3, padx=5, pady = 5, sticky="NSEW")
self.replaceInLable = Label(root, text="String to replace: ")
self.replaceOutLable = Label(root, text="New string: ")
self.replaceInLable.grid(row=7, column=1)
self.replaceOutLable.grid(row=7, column=2)
self.replaceIn = Entry(root, width="20")
self.replaceOut = Entry(root, width="20")
self.replaceIn.grid(row=8, column=1)
self.replaceOut.grid(row=8, column=2)
self.replace = Button(root, text="Replace")
self.replace.grid(row=8,column=3)
self.rightFrame = LabelFrame(root, text="Right Area")
self.rightFrame.grid(row=5, column=4, rowspan=6, columnspan=3, padx=5, pady = 5, sticky="NSEW")
self.quit = Button(root, text="Exit", command=root.quit)
self.quit.grid(row=9, column=6)
root = Tkinter.Tk()
file_zap = FileZap(root)
root.mainloop()
I have tried various alterations but can't nail it! Any help would be much appreciated.
First, the columns / row adapt to there content so an empty one as a zero height/width. If you want to put space between your widgets use the padx and pady options in the .grid method. They can take either one number which will give the padding on both sides or a couple of numbers giving the padding on each side.
Secondly, if you want your widgets to be inside a LabelFrame, you need to create them with this LabelFrame as master instead of the main window.
from Tkinter import LabelFrame, Tk, Button, Label
root = Tk()
# make row 0 resize with the window
root.rowconfigure(0, weight=1)
# make column 0 and 1 resize with the window
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
# create LabelFrames
top_frame = LabelFrame(root, text="top")
left_frame = LabelFrame(root, text="left")
right_frame = LabelFrame(root, text="right")
top_frame.grid(row=0, column=0, columnspan=2, padx=10, pady=(10,4), sticky="nsew")
left_frame.grid(row=1, column=0, padx=(10,4), pady=4, sticky="nsew")
right_frame.grid(row=1, column=1, padx=(4,10), pady=4, sticky="nsew")
#create widgets inside top_frame
Label(top_frame, text="I'm inside top_frame").pack()
Button(top_frame, text="Top").pack()
#create widgets inside left_frame
Label(left_frame, text="I'm inside left_frame").pack()
Button(left_frame, text="Left").pack()
#create widgets inside top_frame
Label(right_frame, text="I'm inside right_frame").pack()
Button(right_frame, text="Right").pack()
Button(root, text="Quit", command=root.destroy).grid(row=2, column=0,
columnspan=2, pady=10)
root.mainloop()

Python3.5 -configure a single cell to expand instead of the entire row or column

Picture a 4x4 grid in a tkinter window. I want to expand the cell at row 2, column 2 but not everything else on row 2 or column 2. Im designing a text window with selectable options on the left side in rows 1-15. Making row 2 with weight 1 and column 2 with weight 1 allows my Text widget to expand but so does everything else in row 2 and column 2. Any way around this?
from tkinter import *
root = Tk()
lbl1 = Label(root, text="label1")
lbl1.grid(row=0, column=1)
lbl2 = Label(root, text="label2")
lbl2.grid(row=1, column=0)
lbl3 = Label(root, text="label3")
lbl3.grid(row=3, column=0)
lbl4 = Label(root, text="label4")
lbl4.grid(row=5, column=0)
txt = Text(root, state='disabled', bg='#E8E8E8')
txt.grid(row=1, column=1, padx=10, pady=10, sticky="NSEW", columnspan=2, rowspan=2)
root.rowconfigure(2, weight=1)
root.columnconfigure(2, weight=1)
root.mainloop()
Example 2:
from tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.grid(row=0, column=1)
frame2 = Frame(root)
frame2.grid(row=1, column=0)
frame3 = Frame(root)
frame3.grid(row=1, column=1, rowspan=2, columnspan=2)
lbl1 = Label(frame1, text="label1")
lbl2 = Label(frame2, text="label2")
lbl3 = Label(frame2, text="label3")
lbl4 = Label(frame2, text="label4")
lbl1.grid(row=0, column=1, sticky=N)
lbl2.grid(row=3, column=0, sticky=N)
lbl3.grid(row=5, column=0, sticky=N)
lbl4.grid(row=7, column=0, sticky=N)
txt = Text(frame3, state='disabled', bg='#E8E8E8')
txt.grid(row=0, column=0, padx=10, pady=10, sticky="NSEW", columnspan=2, rowspan=2)
root.rowconfigure(2, weight=1)
root.columnconfigure(2, weight=1)
frame3.rowconfigure(0, weight=1)
frame3.columnconfigure(0, weight=1)
root.mainloop()
Example 2 has everything in the position I want it in but the Text widget does not expand. Is it possible to set a frame to expand when using grid?
Your question asks about a 4x4 grid, but your example shows only two columns. That makes it hard to understand what you want. In the comments you say you simply want the text area of the example to grow and shrink and all the labels together, so that's what I'll address.
The simplest solution is to have an extra row and column to the right and below the text area. Have the text widget span into those areas, and give those areas a weight of 1. That means that, as the window changes size, any extra space is allocated to areas not occupied by buttons.
pro tip: I find layout problems much easier to visualize and solve when all of the layout code is together.
It would look something like this:
lbl1.grid(row=0, column=1)
lbl2.grid(row=1, column=0)
lbl3.grid(row=2, column=0)
lbl4.grid(row=3, column=0)
txt.grid(row=1, column=1, padx=10, pady=10, sticky="NSEW", columnspan=2, rowspan=4)
root.rowconfigure(4, weight=1)
root.columnconfigure(2, weight=1)
I think your layout problems might be better solved by using pack instead of grid for part of the layout. For example, you might start with three areas: a toolbar, a side panel, and then main area with the text widget:
toolbar = Frame(root, ...)
side = Frame(root, ...)
main = Frame(root, ...)
toolbar.pack(side="top", fill="x")
side.pack(side="left", fill="y")
main.pack(side="right", fill="both", expand=True)
With that you now have three relatively independent areas. You can use pack or grid in each of these frames independently, making it much easier to keep track of rows and columns.
One way around it would be to make your grid twice as large, setting the things you want to be expandable to span two columns/rows.
I.e. you use exclusively odd numbered rows/columns for griding things ([1,1][1,3],[3,1][3,3]...) and you set even-numbered rows/columns to have weight. Anything you want to expand in one or both directions gets a columnspan or rowspan of 2, pushing it into a row/column which may expand as needed.
With the information everyone has provided I was able to come up with a solution. I left the Text widget on the main window instead of in a frame and put my labels/tools in frames. Basically using the fact that a frame will not expand to lock down the labels. Now when the window is expanded only the widget grows.
from tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.grid(row=0, column=1)
frame2 = Frame(root)
frame2.grid(row=1, column=0)
lbl1 = Label(frame1, text="label1")
lbl2 = Label(frame2, text="label2")
lbl3 = Label(frame2, text="label3")
lbl4 = Label(frame2, text="label4")
lbl1.grid(row=0, column=1, sticky=N)
lbl2.grid(row=3, column=0, sticky=N)
lbl3.grid(row=5, column=0, sticky=N)
lbl4.grid(row=7, column=0, sticky=N)
txt = Text(root, state='disabled', bg='#E8E8E8')
txt.grid(row=1, column=1, padx=10, pady=10, sticky="NSEW", columnspan=2, rowspan=2)
root.rowconfigure(2, weight=1)
root.columnconfigure(2, weight=1)
root.mainloop()
Thanks for all the help.

Categories