How to swap between pages / windows in Tkinter - python

I have tried googling and everyone seems to have structured their code completely differently. I understand the base level tkinter, however I do not understand how people are using classes and def's to swap pages. How can I swap from my main window to my second one? (and not open the second one after the main is closed)
import tkinter as tk
main = tk.Tk()
main.title("Main Program")
firstlabel = tk.Label(main, text="This is a program!")
firstlabel.pack()
main.mainloop()
second = tk.Tk()
second.title("Second Program")
firstlabel = tk.Label(second, text="This is another program!")
firstlabel.pack()
second.mainloop()
EDIT: (solution)
import tkinter as tk
class Application(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=("Consolas", 30))
label.pack(pady=10,padx=10)
button = tk.Button(self, text="Visit Page 1", command=lambda: controller.show_frame(PageOne))
button.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page One!!!", font=("Consolas", 30))
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home", command=lambda: controller.show_frame(StartPage))
button1.pack()
app = Application()
app.mainloop()

One way do this is by clearing everything (every widget), with this function:
def clear(app):
# Delete everything else in app
widget_list = app.winfo_children()
for item in widget_list:
if item.winfo_children():
widget_list.extend(item.winfo_children())
for item in widget_list:
item.pack_forget()
And then puting in the new window you want to swap to (every window should hav its own frame to make it simpler).

Try this::::
tk.Toplevel(main)

Related

Is it possible to center a frame in the middle of the screen in Python Tkinter?

I am a high school student coding in Python and I have a very simple GUI application, and my program is different from others in that it doesn't use normal Tkinter windows. I used frames so that my code would flow more, but now I want to know is it possible to make each frame pop up in the center of my screen and not off to the top left. I am still new to this so let me know if you need anything more. Thank you <3
Here is my code:
import tkinter as tk
from tkinter import font as tkfont
LARGE_FONT = ("Verdana", 12)
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
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"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()

Python tkinter code - frames with imported image buttons

Currently the program opens up an empty blank window when trying to import images as buttons. Without trying to import the image as buttons, the code works fine however. Can anyone help fix this code up or point me in the right direction?
from tkinter import*
root = Tk()
class app(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = 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, SignIn, SignUp):
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(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Start Page")
label.pack(pady=10,padx=10)
img1 = PhotoImage(file="signinbtn.png")
button = Button(self, image=img1,
command=lambda: controller.show_frame(SignIn))
button.pack()
img2 = PhotoImage(file="signupbtn.png")
button2 = Button(self, image=img2, text="Sign Up",
command=lambda: controller.show_frame(SignUp))
button2.pack()
class SignIn(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Sign In")
label.pack(pady=10,padx=10)
button1 = Button(self, text="Back to Start Page",
command=lambda: controller.show_frame(StartPage))
button1.pack()
class SignUp(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="Sign Up")
label.pack(pady=10,padx=10)
button1 = Button(self, text="Back to Start Page",
command=lambda: controller.show_frame(StartPage))
button1.pack()
root.mainloop()
The empty window is created by the second code line:
root = Tk()
Apart from this line you have just class definitions. As you never instantiate any of the classes no code from any class is run.

Tkinter GUI frames - autoloading frame using 'after'?

I've been experimenting with some code I found here which lets you navigate between multiple tkinter GUI frames:
Navigating between multiple Tkinter GUI frames
And I'm trying to see if I can autoload a specific frame after a certain amount of time passes, (similar to a sleep screen / screensaver).
I've used the .after method and beginning right after frame.tkraise(). It calls a new class called Autoload, which is currently just a copy of the main App Class SeaofBTCapp.
It works, but the obvious problem with this is that it's popping out the frame into a new window because it's calling this again:
tk.Tk.__init__(self, *args, **kwargs)
I'm a total newb, so I apologize for asking a very obvious question, but what is the best way to keep it from popping out? If I copy the code from one of the Frame classes, it tells me that __init__ is not getting enough arguments. I have tried various (obvious) things, but having trouble wrapping my head around this because it ultimately would have to be a passive function operating in the back of the main app, without hindering other functionality (calling new frames). I'm probably just overthinking this and have missed a very simple and elegant solution. Any thoughts?
Here's the full code, thanks for help!
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()
frame.after(2000, Autoload) #####
class Autoload(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()
frame.after(2000, Autoload) #####
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()

Expand Tkinter Frame

I have a basic application using tkinter with python (3.5). I want the application to be run in full screen, and have multiple windows to switch through. So far this is what I have.
import tkinter as tk
class Window(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Movie Kiosk")
self.attributes("-fullscreen", True)
self.resizable(width=False, height=False)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=1)
self.frames = {}
for f in (StartPage, PageOne):
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="Main Page", font=("Verdana",48))
label.place(relx=0.5, y=0, anchor=tk.N)
button = tk.Button(self, text="Go to page 1",
command=lambda: controller.show_frame(PageOne))
button.place(relx=1, rely=1, anchor=tk.SE)
exitButton = tk.Button(self, text="Close Program", command=exit)
exitButton.place(relx=0, rely=1, anchor=tk.SW)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page 1")
label.pack()
button = tk.Button(self, text="Back to home",
command=lambda: controller.show_frame(StartPage))
button.pack()
app = Window()
app.mainloop()
When I run the application, the program loads in full screen mode, however the frame and all its widgets are packed tightly in the top left corner of the screen. Not sure why this is happening, I have messed around changing properties of my my "app" and my frames. If someone could tell me whats wrong or direct me to a place where I can find an answer it would be very much so appreciated. Thanks.
Not sure why this fixes it...
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
Adding this code after packing the container fixes the problem.

Python tkinter callback

I have a container with a set of frames, that provide me with two pages (main page and an info page.) Buttons are used to navigate the pages.
All is working.
I have defined a function to remove folders on the OS. (shutil.rmtree) This function should be called by my button 2 on the main page, but it falls over and is not working.
import tkinter as tk
import shutil
from tkinter import *
TITLE_FONT = ("Helvetica", 18, "bold")
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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 (MainPage, InfoPage,):
frame = F(container, self)
self.frames[F] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(MainPage)
def show_frame(self, c):
'''Show a frame for the given class'''
frame = self.frames[c]
frame.tkraise()
class MainPage(tk.Frame):
def callback(self):
shutil.rmtree('C:\Test', ignore_errors=False)
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
photo = PhotoImage(file='C:\Logo.gif')
label = Label(self, image=photo)
label.Image = photo
label.pack(side=TOP)
button1 = tk.Button(self, text="Info!",
command=lambda: controller.show_frame(InfoPage))
button1.pack(side=LEFT, padx=5, pady=5)
button2 = tk.Button(self, text="Clean!", command=callback)
button2.pack(side=RIGHT, padx=5, pady=5)
class InfoPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Info Page", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Back",
command=lambda: controller.show_frame(MainPage))
button.pack()
if __name__ == "__main__":
app = App()
app.mainloop()

Categories