Changing pages after a delay with Tkinter - python

Unable to change change frames after a delay
How can I use the showFrames method from logoPage class in the code provided below?
class temp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "SOC_Workups")
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 (logoPage, mainPage):
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.showFrame("logoPage")
def showFrame(self, page):
frame = self.frames[page]
frame.tkraise()
class logoPage(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)
canvas = tk.Canvas(self, height=500, width=1000)
canvas.pack()
logo = tk.PhotoImage(file='logo1.png')
background_label = tk.Label(self, image=logo)
background_label.image = logo
background_label.place(relwidth=1, relheight=1)
#parent.showFrame("mainPage")
class mainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
canvas = tk.Canvas(self, height=500, width=1000)
canvas.pack()
app = temp()
app.mainloop()
The app should start with logoPage and then changes to mainPage after 10 secs. I am unable to call the showFrame method from logoPage class.

You have access to showPage() using controller
controller.showFrame("mainPage")
To run with delay you can use root.after(millisecond, callback). In your code it will need lambda to create callback which runs function with arguments`
parent.after(10000, lambda:controller.showFrame("mainPage"))
EDIT: As Bryan Oakley said in comment you can run it without lambda
parent.after(10000, controller.showFrame, "mainPage")
Second argument in after() is callback - function's name without () - and all its arguments are as next arguments in after()
I changed it in code below too.
Full working code:
There is good rule in PEP 8 -- Style Guide for Python Code which suggests to use CamelCaseNames for classes - ie. LogoPage, MainPage, Temp similar to Button, Frame, Button, etc. it helps to recognize class in code. And some tools use speciala color for classes - see colors in code below.
import tkinter as tk
class Temp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "SOC_Workups")
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 (LogoPage, MainPage):
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")
print(self.frames)
self.showFrame("LogoPage")
def showFrame(self, page):
frame = self.frames[page]
frame.tkraise()
class LogoPage(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)
canvas = tk.Canvas(self, height=500, width=1000)
canvas.pack()
logo = tk.PhotoImage(file='logo1.png')
background_label = tk.Label(self, image=logo)
background_label.image = logo
background_label.place(relwidth=1, relheight=1)
#parent.showFrame("mainPage")
#parent.after(10000, lambda:controller.showFrame("MainPage"))
parent.after(10000, controller.showFrame, "MainPage")
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
canvas = tk.Canvas(self, height=500, width=1000)
canvas.pack()
app = Temp()
app.mainloop()

Related

tkinter items not being placed inside frame

I'm having an issue where nothing is being placed in the frame and I'm not sure why as the template works when I tested that and can't see where I have done anything different other than use different widgets
Template used: https://www.semicolonworld.com/question/42826/switch-between-two-frames-in-tkinter
This is my code with most of the items removed other than a couple of examples
import tkinter as tk
from tkinter import *
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=False)
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
def check_user_login():
#code removed
return None
#create a canvas to place images on
canvas = tk.Canvas(self, bg = "#5c5c5c",height = 400,width = 800,bd = 0,highlightthickness = 0,relief = "flat")
canvas.place(x = 0, y = 0)
#login button
button = tk.Button(self, text="Go to the start page",command=lambda: controller.show_frame("PageOne"))
button.place(x = 356, y = 290,width = 89,height = 29)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
#create a canvas to place images on
canvas = Canvas(self,bg = "#5c5c5c",height = 400,width = 800,bd = 0,highlightthickness = 0,relief = "flat")
canvas.place(x = 0, y = 0)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = App()
app.geometry("800x400")
# app.configure(bg = "#5c5c5c")
app.resizable(False, False)
app.mainloop()
Any help would be massively appreciated I've been stuck on this for a while

Tkinter config from a different class

I have shortened my code to 100 lines but in a much larger file I cannot properly use the config function to change a label in a different class. If you run my file here you will see I am attempting to change 0 to a different str value.
from tkinter import *
class App(Tk):'
def __init__(self, *args, **kwargs):
#declare our frame
Tk.__init__(self, *args, **kwargs)
#Setup the frame
container = Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
#declare the object to hold the frames
self.frames = {}
#loop through the list of frames
for i in (Page_One, Page_Two):
frame = i(container, self)
self.frames[i] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
#start with the home page
self.show_frame(Page_One)
def show_frame(self, context):
'''This method will show the frame that is passed through it. \n
Used in button by implementing lamda'''
frame = self.frames[context]
frame.tkraise()
class Page_One(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
def change_value(value):
Page_Two.label.config(text = value)
print(value)
Button(self, text='Set value to 1',command=lambda *args: change_value('1')).pack()
Button(self, text='Set value to 2',command=lambda *args: change_value('2')).pack()
Button(self, text='Set value to 3',command=lambda *args: change_value('3')).pack()
Button(self, text='Page 2', command = lambda: controller.show_frame(Page_Two)).pack()
class Page_Two(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text = '0')
label.pack()
Button(self, text='Page 1',command = lambda: controller.show_frame(Page_One)).pack()
app = App()
app.mainloop()

Tkinter widgets all pack in the same Frame

I am trying to make a fairly simple GUI with multiple windows. I have my windows built as classes just with a label in each one for now. I can't seem to figure out why when I run my program it packs all of the labels on the "StartPage" and none of the other windows have anything in them. It could be that I have my classes configured incorrectly?
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, WeeklyBudget, LongtermSavings, Investments):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.ShowFrame(StartPage)
def ShowFrame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
start_label = tk.Label(self, text = 'Welcome to Finance Track!')
start_label.pack()
week_btn = tk.Button(self, text = 'Weekly Budgeting', command =lambda: controller.ShowFrame(WeeklyBudget))
savings_btn = tk.Button(self, text = 'Longterm Savings', command = lambda: controller.ShowFrame(LongtermSavings))
invest_btn = tk.Button(self, text = 'Investments', command = lambda: controller.ShowFrame(Investments))
week_btn.pack(pady = 10, padx = 10)
savings_btn.pack(pady = 10, padx = 10)
invest_btn.pack(pady = 10, padx = 10)
class WeeklyBudget(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Weekly Budget')
label.pack()
add_btn = tk.Button(text = 'add new week')
add_btn.pack()
class LongtermSavings(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Longterm Savings')
label.pack()
class Investments(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Investments')
label.pack()
app = application()
app.mainloop()
The current outcome as I described earlier is just one window with all the labels and all the buttons in it.
As jasonharper mention you aren't defining the parents (aka master) of many widgets.
class Investments(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Investments')
label.pack()
Using this Investments class for example, your label will be given the window as it's parents by default, to set it's parent to the newly created frame, just do the following:
class Investments(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = 'Welcome to your Investments')
label.pack()

Updating frames on Python's Tkinter

I need some help updating frames. I did some research (update() and update_idletasks()) but so far nothing has worked. I could be implementing these methods incorrectly. This is what i have so far...
import tkinter as tk
LARGE_FONT = ("Verdana", 12)
class controller(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
self.minsize(width=300, height=300)
container.grid()
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {} # Store all the frames
for F in (StartPage, CustomerLocation, CustomerPickDate):
frame = F(container, self) # F is the classes
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage) # Make Start Page on the top
def show_frame(self, cont): # Used to bring the given frame to the top/ show frame
frame = self.frames[cont] # Access the dic of all the frames
frame.tkraise()
def get_page(self, page_class): # Get access to the page and its attributes
return self.frames[page_class]
def combine_funcs(self, *funcs): # Run multi funcs at one time (attach to a button!)
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
def updateFrame(self,frame):
selectedFrame = self.frames[frame]
selectedFrame.update_idletasks()
#frame.update_idletasks(self)
print("hit")
class CustomerLocation(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.myparent = parent
self.controller = controller
self.configure(background='#ED7D3B')
# ________________________________________________________________
# self.variableLocation is what I want in the next frame
# ________________________________________________________________
self.variableLocation = tk.StringVar(self)
self.variableLocation.set("Select")
alist = ["Blackwood", "Camden", "Philadelphia"]
locationOptionMenu = tk.OptionMenu(self, self.variableLocation, *alist)
locationOptionMenu.pack()
#print(self.variableLocation.get())
nextButton = tk.Button(self, text="Next",
command=lambda: controller.combine_funcs(controller.updateFrame(CustomerPickDate),
controller.show_frame(CustomerPickDate)
))
nextButton.configure(highlightbackground='#ED7D3B')
nextButton.pack()
backButton = tk.Button(self, text="Back",
command=lambda: controller.show_frame(StartPage))
backButton.configure(highlightbackground='#ED7D3B')
backButton.pack()
At this point self.variableLocation should be one of the alist variables. I used the controller.get_page(FRAME) to grab that value. I want to use this value as a label on the next frame.
class CustomerPickDate(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller # Help Access the controller + its methods
self.CustomerLocation = self.controller.get_page(CustomerLocation) # Access to Frame CustomerLocation
self.variableLocation = self.CustomerLocation.variableLocation
print(self.variableLocation.get())
label = tk.Label(self, text="Select Date", font=LARGE_FONT)
label.pack(pady=10, padx=10)
# _______________________________________________________
# I want the self.variableLocation from the pervious frame
# to be here!___________________________________________
self.label2 = tk.Label(self, text="TEST %s" % self.variableLocation.get()) # NEED FIXING/ ABLE TO UPDATE
self.label2.pack()
self.label2.update()
NextButton = tk.Button(self, text="Next")
NextButton.pack()
BackButton = tk.Button(self, text="Back",
command=lambda: controller.show_frame(CustomerLocation))
BackButton.pack()
I am very new to Tkinter, so any feed back would be great!

Can't access variable from other class - tkinter

I'm attempting to write a program in tkinter where the user clicks on a button with their name and a verification page shows it to them. The problem I'm having is that the variable is either resetting or I'm accessing it wrong:
import tkinter as tk
from tkinter import *
from tkinter import ttk
LARGE_FONT = ("Times New Roman", 12)
NORM_FONT = ("Times New Roman", 10)
root = Tk()
root.withdraw()
class DIS(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="")
tk.Tk.wm_title(self, "program")
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, contactQues, nameVerify):
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)
button2 = ttk.Button(self, text = "Name Select",
command=lambda: controller.show_frame(contactQues))
button2.pack()
class contactQues(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
global name
name = StringVar()
label1 = tk.Label(self, text = "Select Your Name", font = LARGE_FONT)
label1.pack(pady=10, padx=10)
button2 = ttk.Button(self, text = "Bojangles", command = self.bojangles)
button2.pack(pady=5)
def bojangles(self):
name.set("Mr. Bojangles")
self.controller.show_frame(nameVerify)
#
#Many other names to select
#
class nameVerify(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
namename = name.get()
label5 = tk.Label(self, text = "Your Name:", font = LARGE_FONT)
label5.pack(pady=10, padx=10)
labelcontact = tk.Label(self, text = namename, font = NORM_FONT)
labelcontact.pack()
app = DIS()
app.mainloop()
So, in essence, what I want to happen is:
- Program runs and user presses "Name select", user selects their name, and the final page shows their selection.
I've tried messing with globals, textvariables for the labelcontact label, StringVar(), etc. and can't seem to peg this one down.
Is there a better way to do this? Or am I doing something inherently wrong?
Thank you for any help.
I suggest making name an attribute of the DIS class. Then your StartPage and nameVerify instances can access it via their controller attributes. If you want labelcontact to update automatically whenever name does, use the textvariable attribute.
Additionally, you need to delete your root = Tk() and root.withdraw() lines. I don't know why, but as long as they're there, the labelcontact Label won't properly update. They don't appear to do anything in any case - hopefully they aren't crucial to your actual code.
import tkinter as tk
from tkinter import *
from tkinter import ttk
LARGE_FONT = ("Times New Roman", 12)
NORM_FONT = ("Times New Roman", 10)
class DIS(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="")
tk.Tk.wm_title(self, "program")
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.name = StringVar()
self.frames = {}
for F in (StartPage, contactQues, nameVerify):
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)
button2 = ttk.Button(self, text = "Name Select",
command=lambda: controller.show_frame(contactQues))
button2.pack()
class contactQues(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label1 = tk.Label(self, text = "Select Your Name", font = LARGE_FONT)
label1.pack(pady=10, padx=10)
button2 = ttk.Button(self, text = "Bojangles", command = self.bojangles)
button2.pack(pady=5)
def bojangles(self):
self.controller.name.set("Mr. Bojangles")
self.controller.show_frame(nameVerify)
#
#Many other names to select
#
class nameVerify(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label5 = tk.Label(self, text = "Your Name:", font = LARGE_FONT)
label5.pack(pady=10, padx=10)
labelcontact = tk.Label(self, textvariable = self.controller.name, font = NORM_FONT)
labelcontact.pack()
app = DIS()
app.mainloop()

Categories