I made the following changes to your code to get it working:
Gridded the root window so that container would occupy the entire space in the window.
#Gridding the tkinter window
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
Made container expand in all directions using sticky = 'nsew'.
container.grid(row=0, column=0, sticky = 'nsew')
Modified __init__ and added tkraise to all the Page classes.
I will use the below block of code for explanation purposes.
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# label of frame Layout 2
welcome = ttk.Label(self, text ="Welcome!", font = LARGEFONT)
welcome.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="Page 1", command = lambda : controller.show_frame(Page1))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Page 2", command = lambda : controller.show_frame(Page2))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
In the __init__ method, self.frame_buttons is created and all the buttons are added to it. It is displayed using .grid and then immediately removed with .grid_remove(). The advantage of using .grid_remove() is that the grid options are remembered and we can directly use .grid() to display the frame in future.
In the tkraise method, the frame is displayed, lifted to the top and then tk.Frame.tkraise(self) is used to call the in-built method.

Working Code:
from cgitb import text
import tkinter as tk
from tkinter import ttk
LARGEFONT =("Verdana", 35)
class tkinterApp(tk.Tk):
# __init__ function for class tkinterApp
def __init__(self, *args, **kwargs):
# __init__ function for class Tk
tk.Tk.__init__(self, *args, **kwargs)
#Gridding the tkinter window
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
# creating a container
container = tk.Frame(self)
container.grid(row=0, column=0, sticky = 'nsew')
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
# initializing frames to an empty array
self.frames = {}
# iterating through a tuple consisting
# of the different page layouts
for F in (StartPage, Page1, Page2):
frame = F(container, self)
# initializing frame of that object from
# startpage, page1, page2 respectively with
# for loop
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky ="nsew")
self.show_frame(StartPage)
# to display the current frame passed as
# parameter
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# label of frame Layout 2
welcome = ttk.Label(self, text ="Welcome!", font = LARGEFONT)
welcome.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="Page 1", command = lambda : controller.show_frame(Page1))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Page 2", command = lambda : controller.show_frame(Page2))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
# second window frame page1
class Page1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Page 1", font = LARGEFONT)
label.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="StartPage", command = lambda : controller.show_frame(StartPage))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Page 2", command = lambda : controller.show_frame(Page2))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
# third window frame page2
class Page2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Page 2", font = LARGEFONT)
label.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="Page 1", command = lambda : controller.show_frame(Page1))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Startpage", command = lambda : controller.show_frame(StartPage))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
# Driver Code
app = tkinterApp()
app.geometry("800x425")
app.mainloop()

Videos
I made the following changes to your code to get it working:
Gridded the root window so that container would occupy the entire space in the window.
#Gridding the tkinter window
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
Made container expand in all directions using sticky = 'nsew'.
container.grid(row=0, column=0, sticky = 'nsew')
Modified __init__ and added tkraise to all the Page classes.
I will use the below block of code for explanation purposes.
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# label of frame Layout 2
welcome = ttk.Label(self, text ="Welcome!", font = LARGEFONT)
welcome.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="Page 1", command = lambda : controller.show_frame(Page1))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Page 2", command = lambda : controller.show_frame(Page2))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
In the __init__ method, self.frame_buttons is created and all the buttons are added to it. It is displayed using .grid and then immediately removed with .grid_remove(). The advantage of using .grid_remove() is that the grid options are remembered and we can directly use .grid() to display the frame in future.
In the tkraise method, the frame is displayed, lifted to the top and then tk.Frame.tkraise(self) is used to call the in-built method.

Working Code:
from cgitb import text
import tkinter as tk
from tkinter import ttk
LARGEFONT =("Verdana", 35)
class tkinterApp(tk.Tk):
# __init__ function for class tkinterApp
def __init__(self, *args, **kwargs):
# __init__ function for class Tk
tk.Tk.__init__(self, *args, **kwargs)
#Gridding the tkinter window
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
# creating a container
container = tk.Frame(self)
container.grid(row=0, column=0, sticky = 'nsew')
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
# initializing frames to an empty array
self.frames = {}
# iterating through a tuple consisting
# of the different page layouts
for F in (StartPage, Page1, Page2):
frame = F(container, self)
# initializing frame of that object from
# startpage, page1, page2 respectively with
# for loop
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky ="nsew")
self.show_frame(StartPage)
# to display the current frame passed as
# parameter
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# label of frame Layout 2
welcome = ttk.Label(self, text ="Welcome!", font = LARGEFONT)
welcome.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="Page 1", command = lambda : controller.show_frame(Page1))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Page 2", command = lambda : controller.show_frame(Page2))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
# second window frame page1
class Page1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Page 1", font = LARGEFONT)
label.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="StartPage", command = lambda : controller.show_frame(StartPage))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Page 2", command = lambda : controller.show_frame(Page2))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
# third window frame page2
class Page2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Page 2", font = LARGEFONT)
label.grid(row = 0, column = 2)
#Creating a frame exclusively for the buttons
self.frame_buttons = tk.Frame(parent)
self.frame_buttons.grid(row = 1, column = 0, columnspan = 3)
self.frame_buttons.grid_remove()
#Gridding self.frame_buttons
self.frame_buttons.grid_columnconfigure((0,1), weight = 1)
self.frame_buttons.grid_rowconfigure(0, weight = 1)
button1 = ttk.Button(self.frame_buttons, text ="Page 1", command = lambda : controller.show_frame(Page1))
button1.grid(row = 0, column = 0, padx = 10, pady = 10)
button2 = ttk.Button(self.frame_buttons, text ="Startpage", command = lambda : controller.show_frame(StartPage))
button2.grid(row = 0, column = 1, padx = 10, pady = 10)
def tkraise(self):
self.frame_buttons.grid()
self.frame_buttons.tkraise()
tk.Frame.tkraise(self)
# Driver Code
app = tkinterApp()
app.geometry("800x425")
app.mainloop()

You are using grid along with pack. You should never mix these two layout managers as it results in unknown buggy behiviour. Maybe your code will work after culling that pack call.
Causing a widget to appear requires that you position it using with what Tkinter calls "geometry managers". The three managers are grid, pack and place. Each has strengths and weaknesses. These three managers are implemented as methods on all widgets.
grid, as its name implies, is perfect for laying widgets in a grid. You can specify rows and columns, row and column spans, padding, etc.
Example:
b = Button(...)
b.grid(row=2, column=3, columnspan=2)
pack uses a box metaphor, letting you "pack" widgets along one of the sides of a container. pack is extremely good at all-vertical or all-horizontal layouts. Toolbars, for example, where widgets are aligned in a horizontal line, are a good place to use pack.
Example:
b = Button(...)
b.pack(side="top", fill='both', expand=True, padx=4, pady=4)`
place is the least used geometry manager. With place you specify the exact x/y location and exact width/height for a widget. It has some nice features such as being able to use either absolute or relative coordinates (for example: you can place a widget at 10,10, or at 50% of the widgets width or height).
Unlike grid and pack, using place does not cause the parent widget to expand or collapse to fit all of the widgets that have been placed inside.
Example:
b = Button(...)
b.place(relx=.5, rely=.5, anchor="c")
With those three geometry managers you can do just about any type of layout you can imagine.
astynax is right. To follow the example you gave:
MyButton1 = Button(master, text="BUTTON1", width=10, command=callback)
MyButton1.grid(row=0, column=0)
MyButton2 = Button(master, text="BUTTON2", width=10, command=callback)
MyButton2.grid(row=1, column=0)
MyButton3 = Button(master, text="BUTTON3", width=10, command=callback)
MyButton3.grid(row=2, column=0)
Should create 3 row of buttons. Using grid is a lot better than using pack. However, if you use grid on one button and pack on another it will not work and you will get an error.
Actually in the previous semester I have also made some Tkinter application which is the project given by teacher to us. So I go to some tutorials website of Python and find three methods of placing the widgets on the output screen. The three methods are
1. Pack()
2. Grid()
3. Place() #the best method over Pack() and Grid()
Place() method take the coordinates in the form of the x and y. See this link for more clarification https://www.tutorialspoint.com/python/python_gui_programming.htm
https://www.tutorialspoint.com/python/tk_place.htm
See the bottom of the Page of the given link.The Place() method is defined with its proper arguments. I will prefer the Place() method over Pack() and Grid() because it works like CSS as we use in html, because it take the value of (width,height) and place your widget according to wherever you want.
If you find your answer a thumbs up will be appreciated.
Mine goes like this:
object1 = Tk()
actionBtn = Button(object1, text="Enter", width=15, height=2, command=quit).place(x=0, y=0)
#.place() is the best thing to use, x and y determine the location in terms of geometry.
you can even add an image with .png extension and goes like this:
buttonEnter = PhotoImage(file="buttonEnter.png") #image file must be inserted
buttonEnter1 = Button(object1, image=buttonEnter, width=20, height=4).place(x=0, y=0)
You can pass the row and column by using a lambda expression for the button:
button = Button(..., command=lambda row=i, column=j: doSomething(row, column))
Could you do something like create the grid of buttons up front, but include a hidden button in the blank space? Then when the button is clicked hide the clicked one and display the hidden one. Then you don't have to worry about moving buttons around, unless you need the actual button object to move for some reason.
Edit to enhance answer from comments:
Below is a simple example of hiding a button and it shows how to track the buttons as well, unless I screwed up moving it to the editor. This can be translated to a list or dictionary of buttons or whatever need be. You'd also need to determine find a way to register the local buttons or add some context to know which one to show or hide.
from Tkinter import Button, Frame, Tk
class myButton(Button):
def __init__(self, *args, **kwargs):
Button.__init__(self, *args, command=self.hideShowButton,
** kwargs)
self.visible = True
def hideShowButton(self):
self.visible = False
self.pack_forget()
window = Tk()
frame = Frame(window)
frame.pack()
b1 = myButton(window, text="b1")
b1.pack()
b2 = myButton(window, text="b2")
b2.pack()
b3 = myButton(window, text="b3")
b3.pack()
window.wait_window(window)
print "At the end of the run b1 was %s, b2 was %s, b3 was %s" % (str(b1.visible), str(b2.visible), str(b3.visible))
To center horizontally this should be enough
button.pack(side=TOP)
But to center horizontally and vertically you could use nested frames. Check the following script:
import tkinter as tk
#%% Frames
frameA = tk.Frame(background="#c8c8c8")
frameB = tk.Frame(width=200, height = 200, background="#646464")
# Nested Frame. framebb is created within frameB without width or height
framebb = tk.Frame(frameB, background="#646464")
frameC = tk.Frame(width=100, height = 100, background="bisque")
frameA.pack(side='top', fill=None)
frameB.pack(side='top')
# expand is the key parameter to center the framebb within frameB
framebb.pack(expand=True)
frameC.pack(side='bottom')
#frameA.pack_propagate(False)
frameB.pack_propagate(False)
frameC.pack_propagate(False)
#%% Buttons and Labels
tk.Label(frameA, text = "Text within the frame A").pack()
a = tk.Button(framebb, text = "A").pack()
b = tk.Button(framebb, text = "B").pack()
c = tk.Button(framebb, text = "C").pack()
d = tk.Button(frameC, text = "D").pack()
e = tk.Button(frameC, text = "E").pack()
tk.mainloop()

Another approach could be using the .grid() method
button.grid(row=1,col=0)
the values of row=1,col=0 depend of the position of the other widget in your window
or you can use .place(relx=0.5, rely=0.5, anchor=CENTER)
button.place(relx=0.5, rely=0.5, anchor=CENTER)
Notice that the parameter anchor is referencing the a relative position to the object (in this case button). anchor is not referencing to a position in the window. You could think that the button is a ship that has several anchors so you should choose a coordinate and which anchor you want to fix in that coordinate.
Example using .place():
from tkinter import * # Use this if use python 3.xx
#from Tkinter import * # Use this if use python 2.xx
a = Button(text="Center Button")
b = Button(text="Top Left Button")
c = Button(text="Bottom Right Button")
# You can use the strings the referencing the relative position on the button
# strings = n, ne, e, se, s, sw, w, nw, c or center
# Or you can use the constants of tkinter
# N, NE, E, SE, S, SW, W, NW, CENTER
a.place(relx=0.5, rely=0.5, anchor=CENTER)
b.place(relx=0.0, rely=0.0, anchor=NW)
c.place(relx=1.0, rely=1.0, anchor=SE)
mainloop()

this is slightly old now, you have to do this:
import tkinter as tk #you can do 'from tkinter import *', any is fine
btn = tk.Button(text = "Centered Button")
btn.place(relx=0.5, rely=0.5, anchor='center')