I am new to object oriented python programming. Currently I am using Python 3. I want to create an app which has multiple pages. I am able to navigate between pages but find it difficult to add image in the background.
Please note I don't want to know how to background image in tkinter as I am already able to do it based on the following code.
bg = PhotoImage(file="images\\bg.png")
label_bgImage = Label(master, image=bg)
label_bgImage.place(x=0, y=0)
I want to know how to add background image to pages when you are defining each window as a class. I put the code to insert background image in the __init__() method of class ABCApp. When I tried to insert the code for adding background image to my existing code, it stopped showing the labels and buttons and now just shows the window.
The following code was my attempt to add an image as background.
import tkinter as tk
from tkinter import ttk
from tkinter import *
class ABCApp(tk.Tk):
def __init__(self,*args,**kwargs):
tk.Tk.__init__(self,*args,**kwargs)
self.geometry("1500x750")
main_frame = tk.Frame(self)
main_frame.pack(side = 'top',fill = 'both',expand ='True')
main_frame.grid_rowconfigure(0,weight=1)
main_frame.grid_columnconfigure(0,weight=1)
bg = PhotoImage(file="images\\bg.png")
label_bgImage = Label(self, image=bg)
label_bgImage.place(x=0, y=0)
self.frames = {}
for F in (HomePage,PageOne,PageTwo):
frame = F(main_frame, self)
self.frames[F] = frame
frame.grid(row=0,column=0,sticky='nsew')
self.show_frame(HomePage)
def show_frame(self,container):
frame = self.frames[container]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self,text='Home Page',font =("Helvetica",20))
label.pack(padx=10,pady=10)
button1 = ttk.Button(self,text = "Page 1",command = lambda: controller.show_frame(PageOne))
button1.pack()
button6 = ttk.Button(self, text="Page 2", command=lambda: controller.show_frame(PageTwo))
button6.pack()
class PageOne(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
label1 = ttk.Label(self, text='Page 1', font=("Helvetica", 20))
label1.pack(padx=10, pady=10)
button2 = ttk.Button(self, text="Back", command=lambda: controller.show_frame(HomePage))
button2.pack()
button5 = ttk.Button(self, text="Page 2", command=lambda: controller.show_frame(PageTwo))
button5.pack()
class PageTwo(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
label2 = ttk.Label(self, text='Page 2', font=("Helvetica", 20))
label2.pack(padx=10, pady=10)
button3 = ttk.Button(self, text="Back", command=lambda: controller.show_frame(HomePage))
button3.pack()
button4 = ttk.Button(self, text="Page 1", command=lambda: controller.show_frame(PageOne))
button4.pack()
app = ABCApp()
app.mainloop()
I would like to have the same or different image to appear as background of each page. Either way I am satisfied.
Since the background image is the same on all the Page classes, an object-oriented way to do it would be to define a base class with the background image on it and then derive all of the concrete Page classes from that instead of a plain tk.Frame. Afterwards, each subclass will need to call its base class' __init__() method before adding whatever widgets are unique to it. In the code below, this new base class is the one named BasePage.
To avoid loading a separate copy of the image file for each BasePage subclass instance, it's only done once and saved as an attribute of the ABCApp class (which is the controller argument being passed to the constructor of each BasePage subclass). Because each page class completely covers-up all the others when it's made visible, each one does need to create its own Label with the background image on it.
Below shows what I mean. (Note I've made the code more PEP 8 - Style Guide for Python Code compliant than what's in your question).
import tkinter as tk
from tkinter.constants import *
from tkinter import ttk
class ABCApp(tk.Tk):
BKGR_IMAGE_PATH = '8-ball.png'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("1500x750")
main_frame = tk.Frame(self)
main_frame.pack(side='top', fill='both', expand='True')
main_frame.grid_rowconfigure(0, weight=1)
main_frame.grid_columnconfigure(0, weight=1)
self.bkgr_image = tk.PhotoImage(file=self.BKGR_IMAGE_PATH)
self.frames = {}
for F in (HomePage, PageOne, PageTwo):
frame = F(main_frame, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(HomePage)
def show_frame(self,container):
frame = self.frames[container]
frame.tkraise()
class BasePage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
label_bkgr = tk.Label(self, image=controller.bkgr_image)
label_bkgr.place(relx=0.5, rely=0.5, anchor=CENTER) # Center label w/image.
class HomePage(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label = ttk.Label(self, text='Home Page', font =("Helvetica",20))
label.pack(padx=10, pady=10)
button1 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button6 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button6.pack()
class PageOne(BasePage):
def __init__(self,parent,controller):
super().__init__(parent, controller)
label1 = ttk.Label(self, text='Page 1', font=("Helvetica", 20))
label1.pack(padx=10, pady=10)
button2 = ttk.Button(self, text="Back",
command=lambda: controller.show_frame(HomePage))
button2.pack()
button5 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button5.pack()
class PageTwo(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label2 = ttk.Label(self, text='Page 2', font=("Helvetica", 20))
label2.pack(padx=10, pady=10)
button3 = ttk.Button(self, text="Back",
command=lambda: controller.show_frame(HomePage))
button3.pack()
button4 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame(PageOne))
button4.pack()
app = ABCApp()
app.mainloop()
Also note that if you wanted each Page class to have a different background image, you would do things a little differently — i.e. each page would become responsible for loading its own image. To do that, the call to the BasePage constructor would need to be passed the name of the image file to be used (as an additional argument in the super().__init__() statement).
Related
I have a tkinter app in which I have a main canvas with multiple pages (all of which are frames). I pull up the different pages by rasing them with the frame.tkraise() command. I now want to add a scrollbar to the whole thing. The scrollbar appears but without a slider and I am not sure if it cna recognize the change of page.
import tkinter as tk
from tkinter import ttk
class Economics(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
tk.Tk.columnconfigure(self, 0, weight=1)
tk.Tk.rowconfigure(self, 0, weight=1)
self.container = tk.Canvas()
self.container.grid(row=0, column=0, sticky="nsew")
self.container.columnconfigure("all", weight=1)
self.container.rowconfigure("all", weight=1)
self.vscrollbar = tk.Scrollbar(orient="vertical", command=self.container.yview)
self.container.configure(yscrollcomman=self.vscrollbar.set)
self.vscrollbar.grid(row=0, column=1, sticky="ns")
self.frames = {}
for F in (StartPage, ExamplePage1, ExamplePage2): # TUPLE OF PAGES
frame = F(self.container, self)
self.frames[F] = frame
self.show_frame(StartPage)
def show_frame(self, cont):
self.container.delete("all")
frame = self.frames[cont]
self.container.create_window(0, 0, anchor="nw", window=frame)
class StartPage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
button_1 = ttk.Button(self, text="Example Page 1",
command=lambda: controller.show_frame(ExamplePage1))
button_1.grid(row=0, column=0)
button_2 = ttk.Button(self, text="Example Page 2",
command=lambda: controller.show_frame(ExamplePage2))
button_2.grid(row=1, column=0)
class ExamplePage1(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
for i in range(50):
label = tk.Label(self, text="Button {} of 50".format(i+1))
label.grid(row=i, column=0)
button_back = ttk.Button(self, text="Back",
command=lambda: controller.show_frame(StartPage))
button_back.grid(row=0, column=1)
class ExamplePage2(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
for i in range(35):
label = tk.Label(self, text="Button {} of 35".format(i+1))
label.grid(row=i, column=0)
button_back = ttk.Button(self, text="Back",
command=lambda: controller.show_frame(StartPage))
button_back.grid(row=0, column=1)
app = Economics()
app.geometry("800x600")
app.resizable(True, True)
app.mainloop()
In this example file you can see the basic structure of my app with some example widgets and buttons. The scrollbar shows but without the slider. What do I have to change to get a working scrollbar for all pages.
Later on I'm planning to get a horizontal scrollbar as well.
You can't scroll items added to a canvas with pack, place, or grid. A canvas can only scroll items added via the canvas create_* functions, such as create_window.
I am writing a tkinter app in Python 3.7, but I haven't worked with GUI before and I am not very experienced. I want to add a canvas with a vertical scrollbar to only one of my three windows. Pages are interconnected via buttons - when I press a button on my StartPage, it takes me to PageOne, and this way I have buttons that take me to the different pages. Each page is a separete class within the main container, and depending on which button I click on (PageOne, PageTwo, PageThree), that page is brought up using show_frame and tkraise. Since all the pages are in one container, I don't know how to implement a scrollbar to just one page within that container. I found an interesting piece of code for the scrollbar here https://gist.github.com/bhaskar-nair2/94b2d4dd511a1cd38ecde9c9481c4b28 but I didn't manage to integrate this into my code. I only need a scrollbar in PageOne window. I would be very grateful for any help.
Here is a part of my code:
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import pandas as pd
import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
import scipy as sp
import numpy as np
from matplotlib.ticker import NullFormatter
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
NORM_FONT = ("Helvetica", 10)
SMALL_FONT = ("Helvetica", 8)
class MyApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Data Visualisation App")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo, PageThree):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
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 = tk.Label(self, text="Start Menu", font=NORM_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button2 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
button3 = ttk.Button(self, text="Page 3",
command=lambda: controller.show_frame(PageThree))
button3.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = ttk.Button(self, text="Back to Start Page",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = ttk.Button(self, text="Back to Start Page",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame(PageOne))
button2.pack()
class PageThree(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = ttk.Button(self, text="Back to Start Page",
command=lambda: controller.show_frame(StartPage))
button1.pack()
app = MyApp()
app.lift()
app.mainloop()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = ttk.Button(self, text="Back to Start Page",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = ttk.Button(self, text="Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
self.frame = VerticalScrolledFrame(self) <--- here!!!
self.frame.pack() <--- here!!!
Where VerticalScrolledFrame is from the repo you linked, I just turned all the orient and position to lowercase and in strings.
Conceptually, there is no difference between how you place the buttons and the scrollbar. If you want to place something in say PageOne, you will go into the __init__ definition of PageOne and put self in the definition of the frame and pack it.
If you want another point of view, you have a container where you put the pages of your GUI, but those pages are frames, and so can be used as containers themselves for other objects (buttons, labels, scrollbars, other frames etc.).
No matter what values I type in the in the row or column on the .grid method; the text boxes still end up in the same place??
The problem is in the PageFour class at the bottom of the code. I want to be able to place the text boxes where I need them. I am new to working with classes and tkinter so any help would be appreciated.
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import tkinter as tk
from tkinter import ttk
LARGE_FONT = ("Verdana",12)
class SeaofBTCapp (tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self,default="work.ico")
tk.Tk.wm_title(self,"The System")
container = tk.Frame(self)
container.pack(side="top",fill="both",expand = True)
container.grid_rowconfigure(0,weight=1)
container.grid_columnconfigure(0,weight=1)
self.frames = {}
for F in (StartPage,PageOne,PageTwo,PageThree,PageFour):
frame = F (container,self)
self.frames[F] = frame
frame.grid(row=0,column=0,sticky="nsew")
self.show_frame(StartPage)
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)
lable = tk.Label(self,text="Start Page", font=LARGE_FONT)
lable.pack(pady=10,padx=10)
button1 = ttk.Button(self,text="Visit Page 1",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button2 = ttk.Button(self,text="Visit Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
button3 = ttk.Button(self,text="Graph Page",
command=lambda: controller.show_frame(PageThree))
button3.pack()
button4 = ttk.Button(self,text="Tab",
command=lambda: controller.show_frame(PageFour))
button4.pack()
class PageOne(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lable = tk.Label(self,text="Page One!!!", font=LARGE_FONT)
lable.pack(pady=10,padx=10)
button1 = ttk.Button(self,text="Back To Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = ttk.Button(self,text="Page Two",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageTwo(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lable = tk.Label(self,text="Page Two!!!", font=LARGE_FONT)
lable.pack(pady=10,padx=10)
button1 = ttk.Button(self,text="Back To Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = ttk.Button(self,text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
class PageThree(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lable = tk.Label(self,text="Graph Page", font=LARGE_FONT)
lable.pack(pady=10,padx=10)
button1 = ttk.Button(self,text="Back To Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
f = Figure(figsize =(5,5), dpi=100)
a = f.add_subplot(111)
a.plot([1,2,3,4,5,6,7,8],[5,6,1,3,8,9,3,5])
canvas = FigureCanvasTkAgg(f,self)
canvas.show()
canvas.get_tk_widget().pack(side=tk.TOP,fill=tk.BOTH,expand=True)
toolbar = NavigationToolbar2TkAgg(canvas,self)
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP,fill=tk.BOTH,expand=True)
class PageFour(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
tabcontrol= ttk.Notebook(self)
tabcontrol.pack(expand=1,fill='both')
tab1 = ttk.Frame(tabcontrol)
tabcontrol.add(tab1,text='Tab 1')
txtbox1 = ttk.Entry(tab1, width=12, textvariable = tk.StringVar())
txtbox1.grid(column=0,row=3)
txtbox2 = ttk.Entry(tab1, width=12, textvariable = tk.StringVar())
txtbox2.grid(column=0,row=10)
tab2 = ttk.Frame(tabcontrol)
tabcontrol.add(tab2,text='Tab 2')
button1 = ttk.Button(self,text="Back To Home",
command=lambda: controller.show_frame(StartPage))
app = SeaofBTCapp()
app.mainloop ()
They will be placed one beneath each other no matter what You enter for row. Why? If there are no widgets in rows between, tkinter will ignore non-existing rows and it will place rows which have something in them one beneath other.
How to solve this? I see two approaches:
Use place instead of grid (not recommended for beginners, difficult to place widgets)
Use Label widgets and place them in rows between those 2 You really need (which is not very good programming practice)
No matter what values I type in the in the row or column on the .grid method; the text boxes still end up in the same place??
No. They won't. e.g. -
txtbox1.grid(column=0, row=0); txtbox2.grid(column=1, row=1)
vs. txtbox1.grid(column=1, row=1); txtbox2.grid(column=0, row=0)
Not the same place, although it will look identitcal.
Now, considering your using row=3 and row=10 I'm assuming you expect there to be some "gap" between the widgets and rows. There won't be. The widgets will appear to be one row after the other in the grid system.
This question already has answers here:
How to get variable data from a class?
(2 answers)
Closed 6 years ago.
my program is this..
import tkinter as tk
from tkinter import *
TITLE_FONT = ("Helvetica", 18, "bold")
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
self.title(" Allocation")
width, height = self.winfo_screenwidth(), self.winfo_screenheight()
self.geometry('%dx%d+0+0' % (width,height))
self.state('zoomed')
self.wm_iconbitmap('icon.ico')
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, c):
frame = self.frames[c]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
logo = tk.PhotoImage(file="backesh.ppm")
BGlabel = tk.Label(self,image=logo)
BGlabel.image = logo
BGlabel.place(x=0,y=0,width=592,height=450)
label = tk.Label(self, text="This is the start page", font=TITLE_FONT)
label.place(x=0,y=0,width=592,height=44)
frame1 = Frame(self)
Label(frame1, bd=5,bg="black",text=" Enter text : ",font=("Helvetica", 14),fg="light green",width=21).pack(side=LEFT)
emp=Entry(frame1, bd =5,font=("Times New Roman", 14),width=25)
emp.pack(side=LEFT)
frame1.place(x=400,y=160)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame(PageOne))
button2 = tk.Button(self, text="Go to Page two",
command=lambda: controller.show_frame(PageTwo))
button3 = tk.Button(self, text="Exit",
command=self.quit)
button1.place(x=100,y=406,width=200,height=44)
button2.place(x=300,y=406,width=200,height=44)
button3.place(x=500,y=406,width=80,height=44)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
logo = tk.PhotoImage(file="backesh.ppm")
BGlabel = tk.Label(self,image=logo)
BGlabel.image = logo
BGlabel.place(x=0,y=0,width=592,height=450)
label = tk.Label(self, text="This is page one", font=TITLE_FONT)
label.place(x=0,y=0,width=592,height=44)
button1 = tk.Button(self, text="Go to Start Page",
command=lambda: controller.show_frame(StartPage))
#button2 = tk.Button(self, text="Go to Page two",
# command=lambda: controller.show_frame(PageTwo))
button3 = tk.Button(self, text="Exit",
command=self.quit)
button1.place(x=100,y=406,width=200,height=44)
button3.place(x=300,y=406,width=200,height=44)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
logo = tk.PhotoImage(file="backesh.ppm")
BGlabel = tk.Label(self,image=logo)
BGlabel.image = logo
BGlabel.place(x=0,y=0,width=592,height=450)
label = tk.Label(self, text="This is page two", font=TITLE_FONT)
label.place(x=0,y=0,width=592,height=44)
button1 = tk.Button(self, text="Go to Start Page",
command=lambda: controller.show_frame(StartPage))
#button2 = tk.Button(self, text="Go to Page two",
# command=lambda: controller.show_frame(PageTwo))
button3 = tk.Button(self, text="Exit",
command=self.quit)
button1.place(x=100,y=406,width=200,height=44)
button3.place(x=300,y=406,width=200,height=44)
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
i want to take entry text data from StartPage and display it as label in PageOne. How to do it? I am new to this. Please type the code.
Thanks in advance.
Firstly, correct the code of the class PageOne and StartPage and add self.controller = controller to the __init__ function:
class PageOne(tk.Frame):
def __init__(self, parent, controller):
#your code
self.controler = controller
Add self before entry field in StartPage and before label in PageOne:
#entry in StartPage
self.emp=tk.Entry(frame1, bd =5,font=("Times New Roman", 14),width=25)
self.emp.pack(side=tk.LEFT)
#label in PageOne
self.label = tk.Label(self, text="This is page one", font=TITLE_FONT)
self.label.place(x=0,y=0,width=592,height=44)
Then add a function go_to_page_one to StartPage class:
def go_to_page_one(self):
self.controller.SomeVar = self.emp.get() #save text from entry to some var
self.controller.frames[PageOne].correct_label() #call correct_label function
self.controller.show_frame(PageOne) #show page one
On button1 in StartPage class change command to lambda: self.go_to_page_one():
button1 = tk.Button(self, text="Go to Page One",
command=lambda: self.go_to_page_one())
At last add a function correct label to the class PageOne:
def correct_label(self):
self.label.config(text=self.controller.SomeVar) #correct the label
I am using a container class in TKinter to start with a Menu screen and be able to switch to one of two other screens when necessary. It isn't quite working correctly and I'm not sure why.
Here is what my main menu screen looks like:
http://i62.tinypic.com/2nhoju0.jpg (won't let me post images yet)
When I click New Game, it looks like this:
http://i57.tinypic.com/x3tglg.jpg (won't let me post images yet)
Clearly, the new game and continue buttons are not supposed to be there, and there should only be one quit button. There should also be a label at the top kinda like the main menu screen.
Can anyone tell me why this is happening?
Here is the relevant code:
class Battleship():
def __init__(self, root):
self.root = root
self.pages = {}
container = Frame(root)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
for P in (MainMenu, ShipSelect, BattleScreen):
frame = P(container, self)
frame.grid(row=0, column=0, sticky="nsew")
self.pages[P] = frame
self.show_frame(MainMenu)
def show_frame(self, cont):
frame = self.pages[cont]
frame.tkraise()
class MainMenu(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Welcome to PyBattleship!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(root, text='New Game', width=13, command=lambda :controller.show_frame(ShipSelect))
button1.pack()
button2 = Button(root, text='Continue Game', width=13)
button2.pack()
button3 = Button(root, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button3.pack()
class ShipSelect(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.root = root
label = Label(self, text="Please place your ships", font=LARGE_FONT)
button1 = Button(self, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button1.pack()
root = Tk()
root.title('Py-Battleship')
sheet = Battleship(root)
root.mainloop()
I just realized that I was still using 'root' for the button widgets in MainMenu. When I changed the 'roots' to 'self' and added padding to the label in ShipSelect, it seems to work.
class MainMenu(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Welcome to PyBattleship!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(self, text='New Game', width=13, command=lambda controller=controller:controller.show_frame(ShipSelect))
button1.pack()
button2 = Button(self, text='Continue Game', width=13)
button2.pack()
button3 = Button(self, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button3.pack()
class ShipSelect(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Please place your ships", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(self, text='Quit', width=13, command=lambda controller=controller:controller.root.destroy())
button1.pack()
Using a mixture of grid and pack in tkinter is never a good idea, which is one of the reasons your code might be having unpredictable results. Secondly, you are trying to pack the buttons to the root window, rather than one of the frames you have created.