The grid geometry manager needs to know what to do if there's more space than necessary to display the widgets. It does this by allocating the extra space relative to the "weight" of each row and column. For example, if one column has a weight of 3 and another column has a weight of 1, the first column will be given 3 times the amount of extra space as the other column.
By default, rows and columns have a weight of zero. That means if there is extra space -- as in your example -- it goes unused.
The absolute simplest solution to your problem is to give each column an equal non-zero weight so that extra space is evenly distributed. You do that with the columnconfigure (or grid_columnconfigure) method:
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
Since you say you want the label to span all three columns, you need to tell grid that, which you can do by placing the label in column zero and giving it a columnspan of 3:
lbl.grid(row=1,column=0, columnspan=3)
Answer from Bryan Oakley on Stack OverflowThe grid geometry manager needs to know what to do if there's more space than necessary to display the widgets. It does this by allocating the extra space relative to the "weight" of each row and column. For example, if one column has a weight of 3 and another column has a weight of 1, the first column will be given 3 times the amount of extra space as the other column.
By default, rows and columns have a weight of zero. That means if there is extra space -- as in your example -- it goes unused.
The absolute simplest solution to your problem is to give each column an equal non-zero weight so that extra space is evenly distributed. You do that with the columnconfigure (or grid_columnconfigure) method:
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
Since you say you want the label to span all three columns, you need to tell grid that, which you can do by placing the label in column zero and giving it a columnspan of 3:
lbl.grid(row=1,column=0, columnspan=3)
As default cells in grid have no size. You can only set minimal size using
root.columnconfigure(0, minsize=300)
root.columnconfigure(1, minsize=300)
root.columnconfigure(2, minsize=300)
To create big header you can connect 3 cells
lbl.grid(..., columnspan=3)
You can also use widget to cell size using sticky='we'
grid(..., sticky='we')
w = west/left, e = east/right
Working example:
import tkinter as tk
# --- functions ---
def fifties(selection):
data = {
"Intro": "1950's intro",
"Political": "1950's politcal",
"Economic": "1950's economic",
"Social": "1950's social",
"Technological": "1950's technological",
"Aesthetic": "1950's aesthetic",
}
if selection in data:
text_1950['text'] = data[selection]
else:
text_1950['text'] = "Unknow selection: " + selection
def sixties(selection):
data = {
"Intro": "1960's intro",
"Political": "1960's politcal",
"Economic": "1960's economic",
"Social": "1960's social",
"Technological": "1960's technological",
"Aesthetic": "1960's aesthetic",
}
if selection in data:
text_1960['text'] = data[selection]
else:
text_1960['text'] = "Unknow selection: " + selection
def seventies(selection):
data = {
"Intro": "1970's intro",
"Political": "1970's politcal",
"Economic": "1970's economic",
"Social": "1970's social",
"Technological": "1970's technological",
"Aesthetic": "1970's aesthetic",
}
if selection in data:
text_1970['text'] = data[selection]
else:
text_1970['text'] = "Unknow selection: " + selection
# --- main ---
# - init -
root = tk.Tk()
root.configure(bg="turquoise")
root.geometry("900x600")
# - set columns minimal size -
root.columnconfigure(0, minsize=300)
root.columnconfigure(1, minsize=300)
root.columnconfigure(2, minsize=300)
# - header -
lbl = tk.Label(root, text="Pick a Decade", bg="turquoise", fg="hot pink", font=("Times", 40, "bold italic"))
lbl.grid(column=0, row=0, columnspan=3, sticky='we')
# - menus -
options = ["Intro", "Political", "Economic", "Social", "Technological", "Aesthetic"]
var = tk.StringVar(value="1950's")
a = tk.OptionMenu(root, var, *options, command=fifties)
a.grid(column=0, row=2, sticky='we')
var = tk.StringVar(value="1960's")
a = tk.OptionMenu(root, var, *options, command=sixties)
a.grid(column=1, row=2, sticky='we')
var = tk.StringVar(value="1970's")
a = tk.OptionMenu(root, var, *options, command=seventies)
a.grid(column=2, row=2, sticky='we')
# - empty labels for text -
text_1950 = tk.Label(root, bg="turquoise")
text_1950.grid(column=0, row=3)
text_1960 = tk.Label(root, bg="turquoise")
text_1960.grid(column=1, row=3)
text_1970 = tk.Label(root, bg="turquoise")
text_1970.grid(column=2, row=3)
# - start -
root.mainloop()

Videos
There's no trick -- the widget is centered in the area allocated to it by default. Simply place a label in a cell without any sticky attributes and it will be centered.
Now, the other question is, how to get the area it is allocated to be centered. That depends on many other factors, such as what other widgets are there, how they are arranged, etc.
Here's a simple example showing a single centered label. It does this by making sure the row and column it is in takes up all extra space. Notice that the label stays centered no matter how big you make the window.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="This should be centered")
label.grid(row=1, column=1)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(1, weight=1)
if __name__ == "__main__":
root = tk.Tk()
Example(root).grid(sticky="nsew")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
You can get a similar effect by giving a weight to all rows and columns except the one with the label.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="This should be centered")
label.grid(row=1, column=1)
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(2, weight=1)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(2, weight=1)
if __name__ == "__main__":
root = tk.Tk()
Example(root).grid(sticky="nsew")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
There is nothing special required. A widget will be in the middle of it's parent automatically. What is required to to tell the parent to fill all available space.
from tkinter import *
root = Tk()
root.geometry("500x500+0+0")
frmMain = Frame(root,bg="blue")
startbutton = Button(frmMain, text="Start",height=1,width=4)
startbutton.grid()
#Configure the row/col of our frame and root window to be resizable and fill all available space
frmMain.grid(row=0, column=0, sticky="NESW")
frmMain.grid_rowconfigure(0, weight=1)
frmMain.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
This uses grid rather than pack to place the widgets and the grid is configured to fill the entire size of the window. The button will appear in the centre regardless of the size of the window.
You cannot create two instances of Tk. As you observed, you will get two windows. That's not the only problem, just the most obvious one.
You need to pass in a reference to the winget that is to contain these labels. Or, store the root window as a global variable, or as an attribute of an object.
To position the 2 labels side by side i.e label1 and label2:
label1.grid(column=0, row=0)
label2.grid(column=1, row=0)
That should do it
I have had success using both justify and anchor:
Label(self, text=text, justify="left", anchor="w").grid(sticky = W, column=0,row=0)
I think your problem lies in the fact that each time you create a new instance of LabeledFrame, you are placing both the Entry & Label within the same Frame.
The grid settings for this Frame are separate from any other Frame, so it is impossible for LabeledFrames to align columns as they do not have the same values for column widths.
Normally to accomplish what you are after you would simply put sticky = W in the grid options for the Entry widget to left-justify the contents of the cell. However, this will only work for each individual Frame, leaving the contents of each separate LabeledFrame out of alignment.
Easiest way to fix this without changing much code:
You'll want to add a line to your for loop. If you specify a large minimum-width of the column that self.field's Frame is inserted into, you can be sure that things will align how you want them to. I've also added config options to the grid calls within the LabeledEntry class: sticky = W for the Label & sticky = E for the Entry.
Try this out and see if it solves your problem. If you would like the column to take less space simply reduce minsize.
from Tkinter import *
class LabeledEntry(Frame):
def __init__(self, parent, *args, **kargs):
text = kargs.pop("text")
Frame.__init__(self, parent)
Label(self, text=text, justify=LEFT).grid(sticky = W, column=0,row=0)
Entry(self, *args, **kargs).grid(sticky = E, column=1, row=0)
class User_Input:
def __init__(self, parent):
fields = ['Text Label 1', 'This is the text Label 2']
GUIFrame =Frame(parent)
GUIFrame.pack(expand=True, anchor=NW)
parent.minsize(width=350, height=325)
field_index = 1
for field in fields:
self.field = LabeledEntry(GUIFrame, text=field)
self.field.grid(column=0, row=field_index)
self.field.grid_columnconfigure(index = 0, minsize = 150)
field_index += 1
self.Button2 = Button(parent, text='exit', command= parent.quit)
self.Button2.place(x=25, y=300)
root = Tk()
MainFrame =User_Input(root)
root.mainloop()
You should take a divide-and-conquer approach to laying out widgets in a GUI. Don't try to do everything at once or use one geometry manager to coordinate everything in one window. Be methodical, and tackle one small problem at a time.
For example, in your target GUI it appears you have four sections: the contact list, a search box and button, a new contact form, and something in the lower right corner (search results?). If I am correct that those are four distinct areas, start by creating four frames. Use grid to place them in the four corners of the main window. Give each frame a distinct color (for debugging purposes). Now, fiddle with options until those four areas grow and shrink in the way that you want. Make sure you give the columns and rows weight so that they all resize properly.
Now that you've done that, you have four smaller, more manageable layout problems. Now, it could be that I'm wrong -- maybe you have two areas, left and right. Or maybe you have three -the left, and then the upper right and the lower right. For now we'll assume I'm right but the technique remains the same regardless.
It looks like you already have the layout for the contact form, so move those into the upper-right frame. Make sure they all expand and shrink properly when you grown and shrink the window (and thus, you grow and shrink the containing frame).
Once you have done that, work on the next section -- put the contact list in the upper left corner. Again, make sure it all resizes properly. At this point you shouldn't have to worry about the widgets on the right because you already have those sorted out. For this section you don't need grid, you can use pack since it's just a couple widgets stacked on top of each other. However, you can use whichever makes the most sense.
Continue on this way, working on the remaining two corners of the GUI. Be methodical, and tackle small independent sections one at a time.
I did something similar, check it out:
from Tkinter import Tk, N, S, W, E, BOTH, Text, Frame,Label, Button,Checkbutton, IntVar,Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Windows")
Label(text="Contact List").grid(row=0,column=0,columnspan=2)
Text(width=30,height=15).grid(row=1,rowspan=9, column=0,columnspan=2,padx=20)
Button(text="Display Contact").grid(row=10, column=0,columnspan=2,pady=10)
Label(text="Last Name:").grid(row=11, column=0,pady=10)
Entry().grid(row=11,column=1)
Button(text="Search").grid(row=12,column=0,columnspan=2)
Label(text="New Contact").grid(row=0,column=2,columnspan=2)
Label(text="First Name:").grid(row=1,column=2,sticky=E)
Entry().grid(row=1,column=3)
Label(text="Last Name:").grid(row=2,column=2,sticky=E)
Entry().grid(row=2,column=3)
Label(text="Phone #:").grid(row=3,column=2,sticky=E)
Entry().grid(row=3,column=3)
friend_check = IntVar()
Checkbutton(variable=friend_check, command = self.friend_box, text = "Friend").grid(row=4,column=3,sticky=W)
#Label(text="Friend").grid(row=4,column=3,padx=20,sticky=W)
Label(text="Email:").grid(row=5,column=2,sticky=E)
Entry().grid(row=5,column=3)
Label(text="Birthday:").grid(row=6,column=2,sticky=E)
Entry().grid(row=6,column=3)
Button(text="Add Contact").grid(row=7,column=3,sticky=E)
def friend_box(self):
if friend_check.get() == 1:
print '1'
else:
print '0'
def main():
root = Tk()
root.geometry("600x450+900+300")
root.resizable(0,0)
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()