How to change page through my menu bar methods in tkinter? - python

Basically what I'm trying to figure out is, how do I make my menu bar "buttons" change the page?
I've already made the dropdown menu, and the classes with each page. The thing is it works if I create a separate button to change the page, but not when i'm trying to do it through the menu bar?
every tutorial I find is through the buttons, and only the buttons..
I am using python 3.6, with tkinter.
import tkinter as tk
class MyApp(tk.Tk):
def __init__(self, *args, **kwargs, ):
tk.Tk.__init__(self, *args, **kwargs)
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 = {}
menu = tk.Menu(container)
betting = tk.Menu(menu, tearoff=0)
menu.add_cascade(menu=betting, label="Pages")
betting.add_command(label="PageOne",
command=lambda: controller.show_frame(PageOne))
betting.add_command(label="PageTwo",
command=lambda: controller.show_frame(PageTwo))
tk.Tk.config(self, menu=menu)
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, 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="Home")
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="page 1",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button2 = tk.Button(self, text="Page Two",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
# ***** PAGES *****
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Back to Home")
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(Startpage))
button1.pack()
button2 = tk.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)
label = tk.Label(self, text="Page Two")
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(Startpage))
button1.pack()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
app = MyApp()
app.geometry("1200x600")
app.mainloop()
Now I know, I haven't parsed the "controller & parent", right now, but I've tried and tried, and nothing works for me...

The controller is MyApp. Within the definition of MyApp that makes controller be self. Thus, you need to call self.show_frame rather than controller.show_frame.
betting.add_command(label="PageOne",
command=lambda: self.show_frame(PageOne))
betting.add_command(label="PageTwo",
command=lambda: self.show_frame(PageTwo))

Related

How can I make the tkinter window fixed?

This is my current code, and I am struggling to understand where I need to put additional code to make sure that my tkinter window is fixed. Code taken from: https://pythonprogramming.net/change-show-new-frame-tkinter/
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = False)
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, 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="NC's Ice-Cream Shop", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = tk.Button(self, text=">>",
command=lambda: controller.show_frame(PageOne))
button.pack()
#button2 = tk.Button(self, text="Visit Page 2",
# command=lambda: controller.show_frame(PageTwo))
#button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Order Details", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="<<",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text=">>",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Receipt", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="<<",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button2 = tk.Button(self, text="New",
command=lambda: controller.show_frame(StartPage))
button2.pack()
app = SeaofBTCapp()
app.mainloop()
As mentioned in the comments, you simply need to set your root window resizable method to false. In your case it is the SeaofBTCapp class.
For Example:
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.resizable(False,False) # <------------------- added this
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = False)
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, 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="NC's Ice-Cream Shop", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = tk.Button(self, text=">>",
command=lambda: controller.show_frame(PageOne))
button.pack()
#button2 = tk.Button(self, text="Visit Page 2",
# command=lambda: controller.show_frame(PageTwo))
#button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Order Details", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="<<",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text=">>",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Receipt", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="<<",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button2 = tk.Button(self, text="New",
command=lambda: controller.show_frame(StartPage))
button2.pack()
app = SeaofBTCapp()
app.mainloop()

How to reload the frame in tkinter everytime switching the frame?

I am using something similar to bellow code to navigation between windows in my tkinter desktop app. However the problem in bellow approach is that since all the frames are loaded at once, even though when i switch windows, it still returns the previous page. however in my use case i am loading metadata from database(picklist values) so i want to reload each frame whenever i switch the windows? How do i modify this code in such a way that every time i switch to a different frame, it reload the frame again.
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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):
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 Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = tk.Button(self, text="Visit Page 1",
command=lambda: controller.show_frame(PageOne))
button.pack()
button2 = tk.Button(self, text="Visit Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.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)
label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
app = SeaofBTCapp()
app.mainloop()
If you want to recreate each page when it is shown, you have complete control in the show_frame method to do exactly that.
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.container = tk.Frame(self)
self.container.pack(fill="both", expand=True)
self.current_frame = None
self.show_frame(StartPage)
def show_frame(self, new_frame_class):
if self.current_frame:
self.current_frame.destroy()
self.current_frame = new_frame_class(self.container, controller=self)
self.current_frame.pack(fill="both", expand=True)

Displaying an image in only its own frame with tkinter

I'm trying to create a simple GUI with tkinter with buttons and images. I have a startpage with an image and buttons that take you to other pages(frames). The problem is that the image in my startpage persists and displays in the other frames.
The code:
import tkinter as tk
LARGE_FONT = ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.geometry("800x480")
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 Page", font=LARGE_FONT)
label.pack(pady=10, padx=10)
#canvas1 = tk.Canvas(width=600, height=300, bg="gray")
#self.img = tk.PhotoImage(file="mario.png")
#canvas1.create_image(20, 20, image=self.img)
#canvas1.pack()
photo = tk.PhotoImage(file="mario.png")
labelimg = tk.Label(image=photo)
labelimg.image = photo # keep a reference!
labelimg.pack()
button = tk.Button(self, text="Visit Page 1",
command=lambda: controller.show_frame(PageOne))
button.pack()
button2 = tk.Button(self, text="Visit Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
app = SeaofBTCapp()
app.mainloop()
The issue is that you have not specified labelimg's parent therefore, by default it is the main window. As a consequence, your label is packed below your container and therefore is always visible.
Changing
labelimg = tk.Label(image=photo)
into
labelimg = tk.Label(self, image=photo)
in the class StartPage should solve your problem.

How to load another tkinter frame from another class file? Python tkinter

import tkinter as tk
from PageTwoFile import PageTwoClass
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame.grid(row=110, column=110, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def qf(param):
print(param)
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Visit Page 1",
command=lambda: controller.show_frame(PageOne))
button1.pack()
button1 = tk.Button(self, text="Visit Page 2",
command=lambda: controller.show_frame(PageTwo))
button1.pack()
class PageOne(tk.Frame):
def __init__(self, parent,controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Page One", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Two",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
app = SeaofBTCapp()
app.mainloop()
In this example I have a class similiar to PageOne but in another file.
class PageTwoClass(tk.Frame):
def __init__(self, parent,controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Page Two", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
I can run it fine, but when I go to PageTwo I can't go back to PageOne, I get:
NameError: name 'PageOne' is not defined
I assume that is going in to PageTwoFile and does not know how to come back. How to make it read everything?
I am working on a banking system and I have another files(customer,accounts) which are imported in the main file. If I want to change frames for when they are accessed I need them to go back...
The solution is to use the name of the class rather than the actual class itself, so that the different classes don't have to import each other.
A better version of the code you started from, with the modification to use the page name rather than the page class, is here: https://stackoverflow.com/a/7557028/7432

Navigating between multiple Tkinter GUI frames

I found some code online to create a tkinter GUI with multiple frames. I tried to modify the code to include a frame with navigation buttons to be displayed on each frame, rather than repeating the code each time. I keep getting error messages and cannot work out how to connect the navigation buttons to the corresponding frame.
This is the code for the closest I have got:
import Tkinter as tk
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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):
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 Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = tk.Button(self, text="Visit Page 1",
command=lambda: controller.show_frame(PageOne))
button.pack()
button2 = tk.Button(self, text="Visit Page 2",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page Two",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
btns = MainButtonFrame(self,SeaofBTCapp)
btns.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
btns = MainButtonFrame(self,SeaofBTCapp)
btns.pack()
class MainButtonFrame(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Pages = [StartPage,PageOne,PageTwo ]
for button in Pages:
NewButton = tk.Button(self, text=str(button),
command=lambda: controller.show_frame(button))
NewButton.pack()
app = SeaofBTCapp()
app.mainloop()
and the error message I got is:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1536, in __call__
return self.func(*args)
File "<ipython-input-13-dcc5fdbf1581>", line 103, in <lambda>
command=lambda: controller.show_frame(button))
TypeError: unbound method show_frame() must be called with SeaofBTCapp
instance as first argument (got classobj instance instead)
Any help would be much appreciated in suggesting what I am doing wrong in the button commands. If I can get this working I will use it as a framework to build a bigger GUI on. Thanks!
The initializer of MainButtonFrame needs a parent and a controller. The controller must be the instance of the main app, not the class. Change how you create MainButtonFrame to be this:
btns = MainButtonFrame(self,controller)

Categories

Resources