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)
Related
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()
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.
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
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))
I am trying to run another script within a script using a button in tkinter
I have tried two methods one being
import os
class SeaofBTCapp(tk.Tk):
#initilization
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Battery Life Calculator")
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)
#raise each page to the front
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def helloCallBack():
os.system('python test2.py')
#the start page
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = ttk.Button(self, text="Visit Page 1",command=lambda:controller.show_frame(PageOne))
button.pack()
button1 = ttk.Button(self, text="Visit Page 2",command=lambda:controller.show_frame(PageTwo))
button1.pack()
button2 = ttk.Button(self, text="Visit Graph page",command=lambda:controller.show_frame(PageThree))
button2.pack()
button3 = ttk.Button(self, text="execute test",command=lambda:controller.helloCallBack)
button3.pack()
No errors are given but when I hit execute nothing happens
The other method i tried was to
import test2
but it runs the script automatically and it prints "i am a test"
I should note the script i am trying to call is simply a test and just prints "i am a test"
any help is appreciated!
thanks
****edit****
import tkinter as tk
from tkinter import ttk
import test2
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
#initilization
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Battery Life Calculator")
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)
#raise each page to the front
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
#the start page
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = ttk.Button(self, text="Visit Page 1",command=lambda:controller.show_frame(PageOne))
button.pack()
button1 = ttk.Button(self, text="Visit Page 2",command=lambda:controller.show_frame(PageTwo))
button1.pack()
button2 = ttk.Button(self, text="Visit Graph page",command=lambda:controller.show_frame(PageThree))
button2.pack()
button3 = ttk.Button(self, text="execute test",command=test2.main)
button3.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text="Page One", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Back to start page",command=lambda:controller.show_frame(StartPage))
button1.pack()
button1 = ttk.Button(self, text="Visit Page 2",command=lambda:controller.show_frame(PageTwo))
button1.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text="Page One", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Back to Start Page",command=lambda:controller.show_frame(StartPage))
button1.pack()
button1 = ttk.Button(self, text="Back to Page One",command=lambda:controller.show_frame(PageOne))
button1.pack()
class PageThree(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text="Graph Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Back to Start Page",command=lambda:controller.show_frame(StartPage))
button1.pack()
app = SeaofBTCapp()
app.mainloop()
test2.p is as follows
def main():
if __name__ == "__main__":
print("Executing as main program")
print("Value of __name__ is: ", __name__)
main()
Your first method is not recommended for that. If you have another python script you should definitely import it.
About the second method:
My guess is that the script test2.py is written without
if __name__ == "__main__":
main()
And that's why it shoot you message when you import it.