Tkinter: Update variable in next frame - python

Good day StackOverFlow!
I need to update var in next frame, using tkinter after it's was changed.
It's work, if i put code on "Page2" in function. BUT.
Can somebody advice please about this?
p.s. I apologize for the code not being clean enough.
import tkinter as tk
from tkinter import ttk
from tkinter import *
#Main frame
class tkinterApp(tk.Tk):
# __init__ function for class tkinterApp
def __init__(self, *args, **kwargs):
# __init__ function for class Tk
tk.Tk.__init__(self, *args, **kwargs)
# creating a container
container = tk.Frame(self)
self.geometry("450x350")
self.title('tool')
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
# initializing frames to an empty array
self.frames = {}
# iterating through a tuple consisting
# of the different page layouts
for F in (StartPage,
Page2,):
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
class Pages:
global timeStamp
timeStamp = 0
#start page
class StartPage(tk.Frame, Pages):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def TimeFocusIn(event):
timeStampInput.delete(0,"end")
timeInputName = ttk.Label(self,
text = "Enter Time in HHMMSS format:")
timeStampInput = ttk.Entry(self)
timeStampInput.insert(0, "HHMMSS")
timeStampInput.bind("<FocusIn>", TimeFocusIn)
#Save time button
def SaveTime(**kwargs):
global timeStamp
var = StringVar()
timeVarOut = timeStampInput.get()
var.set(timeVarOut)
timeVarOutTxt = ttk.Label(self, text=f'{timeVarOut}')
timeVarOutTxt.grid(row = 7, column = 4, padx = 10, pady = 10)
timeStamp = timeVarOut
saveTimeInputButt = ttk.Button(self,
text = "Save time", command = SaveTime)
timeVarText = ttk.Label(self,
text = "TimeStamp is:")
buttPage2 = ttk.Button(self, text ="Next page",
command = lambda : controller.show_frame(Page2))
#Grid placing
timeInputName.grid(row = 5, column = 1, padx = 10, pady = 10, sticky ="nsew")
timeStampInput.grid(row = 5, column = 2, padx = 10, pady = 10, sticky ="nsew")
saveTimeInputButt.grid(row = 5, column = 4, padx = 10, pady = 10, sticky ="nsew")
buttPage2.grid(row = 6, column = 1, padx = 10, pady = 10)
timeVarText.grid(row = 7, column = 2, padx = 10, pady = 10)
#Page 2
class Page2(tk.Frame, Pages):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Next page")
label.grid(row = 0, column = 4, padx = 10, pady = 10)
timeVarOutTxt = ttk.Label(self, text=f'Timestamp is: {timeStamp}')
timeVarOutTxt.grid(row = 1, column = 2, padx = 10, pady = 10)
button1 = ttk.Button(self, text ="Back",
command = lambda : controller.show_frame(StartPage))
button1.grid(row = 1, column = 1, padx = 10, pady = 10)
# Run GUI
app = tkinterApp()
def message():
app.update()
print(timeStamp)
app.after(20, message)
app.after(20, message)
app.mainloop()

If you want to share data between Frames then you could keep it in tkinterApp as self.timeStamp and then every page will have access using controller.timeStamp
if you want to access it in some function then keep self.controller = controller
But this can't change text in label - you have to do it on your own using
You have to use self. in self.timeVarOutTxt and later in saveTime you can access label in other frame and change it.
self.controller.frames[Page2].timeVarOutTxt['text'] = f'Timestamp is: {self.controller.timeStamp}'
Working code with other changes:
import tkinter as tk # PEP8: `import *` is not preferred
from tkinter import ttk
# --- classes --- # PEP8: all classes after imports
# Main frame # PEP8: one space after `#`
class tkinterApp(tk.Tk):
# __init__ function for class tkinterApp
def __init__(self, *args, **kwargs):
# __init__ function for class Tk
super().__init__(*args, **kwargs)
#self.geometry("450x350")
self.title('tool')
self.time_stamp = 0
# creating a container
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True) # PEP8: inside `()` uses `=` without spaces
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
# initializing frames to an empty array
self.frames = {}
# iterating through a tuple consisting
# of the different page layouts
for F in (StartPage, Page2):
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):
super().__init__(parent)
self.controller = controller
time_input_name = ttk.Label(self, text="Enter Time in HHMMSS format:")
self.time_stamp_input = ttk.Entry(self)
self.time_stamp_input.insert(0, "HHMMSS")
self.time_stamp_input.bind("<FocusIn>", self.time_focus_in)
save_time_input_button = ttk.Button(self, text="Save time", command=self.save_time)
time_var_text = ttk.Label(self, text="TimeStamp is:")
button_page2 = ttk.Button(self, text="Next page", command=lambda:controller.show_frame(Page2))
time_input_name.grid(row=5, column=1, padx=10, pady=10, sticky="nsew")
self.time_stamp_input.grid(row=5, column=2, padx=10, pady=10, sticky="nsew")
save_time_input_button.grid(row=5, column=4, padx=10, pady=10, sticky="nsew")
button_page2.grid(row=6, column=1, padx=10, pady=10)
time_var_text.grid(row=7, column=2, padx=10, pady=10)
def time_focus_in(self, event): # PEP8: `lower_case_names` for functions
self.time_stamp_input.delete(0, "end")
def save_time(self, **kwargs): # PEP8: `lower_case_names` for functions
self.time_var_out_txt = ttk.Label(self, text=self.time_stamp_input.get())
self.time_var_out_txt.grid(row=7, column=4, padx=10, pady=10)
self.controller.time_stamp = self.time_stamp_input.get()
self.controller.frames[Page2].time_var_out_txt['text'] = f'Timestamp is: {self.controller.time_stamp}'
class Page2(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
self.controller = controller
label = ttk.Label(self, text="Next page")
label.grid(row=0, column=4, padx=10, pady=10)
self.time_var_out_txt = ttk.Label(self, text=f'Timestamp is: {controller.time_stamp}')
self.time_var_out_txt.grid(row=1, column=2, padx=10, pady=10)
button1 = ttk.Button(self, text="Back", command=lambda:controller.show_frame(StartPage))
button1.grid(row=1, column=1, padx=10, pady=10)
# --- functions --- # PEP8: all functions after classes (before main code)
def message():
#app.update() # no need it
print(app.time_stamp, end='\r') # print in the same line
app.after(20, message)
# --- main ---
# Run GUI
app = tkinterApp()
app.after(20, message)
app.mainloop()
PEP 8 -- Style Guide for Python Code
EDIT:
Other idea: in every Page add function before_switch() and execute it
def show_frame(self, cont):
frame = self.frames[cont]
frame.before_switch()
frame.tkraise()
and this function in class Page2 could update label always before displaying Page2
import tkinter as tk # PEP8: `import *` is not preferred
from tkinter import ttk
# --- classes ---
# Main frame # PEP8: one space after `#`
class tkinterApp(tk.Tk):
# __init__ function for class tkinterApp
def __init__(self, *args, **kwargs):
# __init__ function for class Tk
super().__init__(*args, **kwargs)
#self.geometry("450x350")
self.title('tool')
self.time_stamp = 0
# creating a container
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True) # PEP8: inside `()` uses `=` without spaces
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
# initializing frames to an empty array
self.frames = {}
# iterating through a tuple consisting
# of the different page layouts
for F in (StartPage, Page2):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.frame = None
self.show_frame(StartPage)
def show_frame(self, cont):
if self.frame:
self.frame.after()
self.frame = self.frames[cont]
self.frame.before()
self.frame.tkraise()
class Page(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
self.controller = controller
def before(self):
"""Run before showing Page."""
pass
def after(self):
"""Run after showing Page."""
pass
class StartPage(Page):
def __init__(self, parent, controller):
super().__init__(parent, controller)
time_input_name = ttk.Label(self, text="Enter Time in HHMMSS format:")
self.time_stamp_input = ttk.Entry(self)
self.time_stamp_input.insert(0, "HHMMSS")
self.time_stamp_input.bind("<FocusIn>", self.time_focus_in)
save_time_input_button = ttk.Button(self, text="Save time", command=self.save_time)
time_var_text = ttk.Label(self, text="TimeStamp is:")
button_page2 = ttk.Button(self, text="Next page", command=lambda:controller.show_frame(Page2))
time_input_name.grid(row=5, column=1, padx=10, pady=10, sticky="nsew")
self.time_stamp_input.grid(row=5, column=2, padx=10, pady=10, sticky="nsew")
save_time_input_button.grid(row=5, column=4, padx=10, pady=10, sticky="nsew")
button_page2.grid(row=6, column=1, padx=10, pady=10)
time_var_text.grid(row=7, column=2, padx=10, pady=10)
def time_focus_in(self, event): # PEP8: `lower_case_names` for functions
self.time_stamp_input.delete(0, "end")
def save_time(self, **kwargs): # PEP8: `lower_case_names` for functions
self.time_var_out_txt = ttk.Label(self, text=self.time_stamp_input.get())
self.time_var_out_txt.grid(row=7, column=4, padx=10, pady=10)
def after(self):
"""Update shared value after showing Page."""
self.controller.time_stamp = self.time_stamp_input.get()
class Page2(Page):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label = ttk.Label(self, text="Next page")
label.grid(row=0, column=4, padx=10, pady=10)
self.time_var_out_txt = ttk.Label(self, text=f'Timestamp is: {controller.time_stamp}')
self.time_var_out_txt.grid(row=1, column=2, padx=10, pady=10)
button1 = ttk.Button(self, text="Back", command=lambda:controller.show_frame(StartPage))
button1.grid(row=1, column=1, padx=10, pady=10)
def before(self):
"""Update label before showing Page."""
self.time_var_out_txt['text'] = f'Timestamp is: {self.controller.time_stamp}'
# --- functions ---
def message():
#app.update() # no need it
print(app.time_stamp, end='\r')
app.after(20, message)
# --- main ---
# Run GUI
app = tkinterApp()
app.after(20, message)
app.mainloop()

Related

(python tkinter) pages with class, variable passed to other page, cant use as label : PY_VAR0

I had a problem with passing a variable from one page to the other, its works now, but if I want to use it on a label, it writes PA_VAR0. I read that ".get()" should be used in that case, but it still doesn't work that way. (with .get() it don't even passes the variable). I tried to set a new variable with tk.StringVar() function, but it still didn't work
import tkinter as tk
from tkinter import ttk
class example(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.shared_data = {
"variable": tk.StringVar()
}
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 (page1, page2):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(page1)
def get_page(self, page_class):
return self.frames[page_class]
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class page1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = ttk.Label(self, text="first page")
label.grid(row=0, column=4, padx=10, pady=10)
button1 = ttk.Button(self, text="turn page",
command=lambda: self.pageturn())
button1.grid(row=3, column=1, padx=10, pady=10)
def pageturn(self):
self.controller.shared_data["variable"] = 'string i wanna pass'
print("variable set here: ", self.controller.shared_data["variable"])
self.controller.show_frame(page2)
class page2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = ttk.Label(self, text=self.controller.shared_data["variable"])
label.grid(row=0, column=4, padx=10, pady=10)
label = ttk.Label(self, text=self.controller.shared_data["variable"].get())
label.grid(row=1, column=4, padx=10, pady=10)
button3 = ttk.Button(self, text=self.controller.shared_data["variable"],
command=lambda: print(self.controller.shared_data["variable"]))
button3.grid(row=8, column=10, padx=10, pady=10)
button2 = ttk.Button(self, text="if fuction sees variable",
command=lambda: self.ifok())
button2.grid(row=9, column=10, padx=10, pady=10)
def ifok(self):
if self.controller.shared_data["variable"] == 'string i wanna pass':
print("ok")
app = example()
app.mainloop()
You overwrite self.controller.shared_data["variable"] by a string inside pageturn():
self.controller.shared_data["variable"] = 'string i wanna pass'
You should use .set() instead:
self.controller.shared_data["variable"].set('string i wanna pass')
Full updated code:
import tkinter as tk
from tkinter import ttk
class example(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.shared_data = {
"variable": tk.StringVar()
}
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 (page1, page2):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(page1)
def get_page(self, page_class):
return self.frames[page_class]
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class page1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = ttk.Label(self, text="first page")
label.grid(row=0, column=4, padx=10, pady=10)
button1 = ttk.Button(self, text="turn page",
command=lambda: self.pageturn())
button1.grid(row=3, column=1, padx=10, pady=10)
def pageturn(self):
self.controller.shared_data["variable"].set('string i wanna pass') ### changed = to .set()
print("variable set here: ", self.controller.shared_data["variable"].get()) ### called .get()
self.controller.show_frame(page2)
class page2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = ttk.Label(self, textvariable=self.controller.shared_data["variable"]) ### changed text to textvariable
label.grid(row=0, column=4, padx=10, pady=10)
label = ttk.Label(self, text=self.controller.shared_data["variable"].get())
label.grid(row=1, column=4, padx=10, pady=10)
button3 = ttk.Button(self, textvariable=self.controller.shared_data["variable"], ### changed text to textvariable
command=lambda: print(self.controller.shared_data["variable"].get()))
button3.grid(row=8, column=10, padx=10, pady=10)
button2 = ttk.Button(self, text="if fuction sees variable",
command=lambda: self.ifok())
button2.grid(row=9, column=10, padx=10, pady=10)
def ifok(self):
if self.controller.shared_data["variable"].get() == 'string i wanna pass': ### called .get()
print("ok")
app = example()
app.mainloop()

How do I enable .grid?

I wanted to position in the username and password such that it is next to each other. In order to achieve that I used the grid method but I keep getting an error that says:
_tkinter.TclError: cannot use geometry manager grid inside .!frame.!adminlogin.!frame which already has slaves managed by pack.
Is there a way I can let it use even grid?
import tkinter as tk
from tkinter import font as tkfont
import PIL.Image
from PIL import ImageTk
from tkinter import *
import tkinter.font as font
import sqlite3, hashlib
from datetime import date
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
self.geometry ("1024x768")
container = tk.Frame(self)
container.pack(fill="both", side= 'top',expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, StudentLogin, AdminLogin):
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
frame = tk.Frame(self, width = 1024, height = 768, bg="teal")
frame.pack(fill="both", expand=True, side="top")
label = tk.Label(frame, text="WELCOME", font=controller.title_font)
label.pack(side="top", fill="x", pady=50)
button1 = tk.Button(frame, text="Admin Login",
command=lambda: controller.show_frame("AdminLogin"), width = 50, height=10, font=30, bg='powder blue')
button2 = tk.Button(frame, text="Student Login",
command=lambda: controller.show_frame("StudentLogin"), width=50, height=10, font=30, bg='powder blue')
button1.pack(pady=10)
button2.pack(pady=10)
class AdminLogin(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
frame = tk.Frame(self, width = 1024, height = 768, bg='teal')
frame.pack(fill="both", side ="top", expand=True)
label = tk.Label(frame, text="Enter username and password to login", font=controller.title_font)
label.pack(side="top", fill="x", pady=30, padx =10)
userLabel = tk.Label(frame, text = "Enter Username: ", font=50)
userLabel.pack(padx=10, pady=10)
userEntry = tk.Entry(frame)
userEntry.pack(padx=10, pady=10)
passwordL = tk.Label(frame, text = "Enter Password: ", font=50)
passwordL.pack(padx=10, pady=10)
passEntry = tk.Entry(frame, show="*")
passEntry.pack(padx=10, pady=10)
button = tk.Button(frame, text="Back",
command=lambda: controller.show_frame("StartPage"), bg='powder blue')
button.pack()
class StudentLogin(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
frame = tk.Frame(self, width = 1024, height = 768, bg='teal')
frame.pack(fill="both", side ="top", expand=True)
label = tk.Label(frame, text="Enter username and password to login", font=controller.title_font)
label.pack(side="top", fill="x", pady=30, padx =10)
button = tk.Button(frame, text="Back",
command=lambda: controller.show_frame("StartPage"), bg='powder blue')
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Unfortunately you cannot mix both the pack and grid methods. You have to only pick one, which you will use throughout that master. Pack is easier to use, but with grid you have more control over where your widgets are going to be displayed in the window. (I would have done this as a comment to your post, not an answer, but i do not have enough reputation to do so) I hope this helps :)

Passing value to tkinter class

This is a part of my actual program. I am trying to write a code that will create few Buttons on loop.
My problem is I am passing a value to a tkinter class but it is not printing the right value instead just prints a ".".
I want to pass "chap" from class PageOne to "class ChapterOne" in the below code it isn't working. I don't have much experience in classes. A help here will be much appreciated.
import tkinter as tk
from PIL import ImageTk, Image
from os import listdir
import yaml
LARGE_FONT = ("Verdana", 12)
grey = "#808080"
offwhite = "#e3e3e3"
hintwa = False
x = ''
class MainBot(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 page in (StartPage, PageOne, ChapterOne):
frame = page(container, self)
print (container)
self.frames[page] = frame
frame.grid(row = 0, column = 0, sticky = 'nsew')
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def yaml_loader(self, filepath):
with open (filepath, "r") as fileread:
self.data = yaml.load(fileread)
return self.data
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, background = offwhite, text= "Start Page", font = LARGE_FONT)
label.pack(pady=10, padx=10)
button_start = tk.Button(self, text = 'NEXT', font = ("default", 15, "bold"), bg='orange', fg = 'white', border=2, height = 2, width = 8, command=lambda: controller.show_frame(PageOne))
button_start.pack()
button_start.place(x=650, y=500)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
index_label = tk.Label(self, text = "~~~~~INDEX~~~~~", font = ("Comicsans", 24, "bold"), background = offwhite)
index_label.pack()
index_label.place(x=200, y=50)
onlyfiles = ['chapter-1.yaml']
for yfiles in onlyfiles:
chap = (yfiles.split("."))[0].split("-")[1]
print (chap)
button_index_one = tk.Button(self, text='Chapter ' + str(chap), font=("default", 14, "bold"), bg='white',
fg='black', border=1, height=2, width=12,
command=lambda: controller.show_frame(ChapterOne(self, chap)))
button_index_one.pack(pady=30, padx=0)
class ChapterOne(tk.Frame):
def __init__(self, parent, chap):
tk.Frame.__init__(self, parent)
print (chap)
app = MainBot()
app.geometry("800x600")
app.mainloop()

How to bind same key action to buttons in different windows?

I have been searching a lot and I still don't know, what is the problem. I have two windows asking for some values and as a result different functions are executed. I tried to bind an "Enter" key to buttons of different windows (so different functions should be executed), but this doesn't work.
Only thing that i could do is to bind key to the whole Frame, then unbind it and bind one more time. It works, but i'm curious why i can't link "Enter" key to separate buttons while no error appear. Thanks in advance!
Here is my code:
import tkinter as tk
class Page(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.shared_data = {
"number_of_frequencies": tk.StringVar(),
"frequencies": []}
container = tk.Frame(self)
container.grid()
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=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 create_entry_widget(self, i):
self.number = tk.StringVar()
self.number.set('')
self.shared_data["frequencies"].append(self.number)
new_widget = tk.Entry(self.master, textvariable=self.number)
return new_widget
def show_frame(self, c):
for frame in self.frames.values():
frame.grid_remove()
frame = self.frames[c]
frame.grid()
global number_of_frequencies
try:
number_of_frequencies = int(self.shared_data["number_of_frequencies"].get())
for i in range(number_of_frequencies):
tk.Label(self.master, text="Frequency "+str(i+1)).grid(row=i, column=0, padx=10, pady=5)
self.entry_widgets = self.create_entry_widget(i)
self.entry_widgets.grid(row=i, column=1, padx=10, pady=5)
page1 = self.get_page(PageOne)
tk.Button(self, text="Exit",
command=lambda: self.quitALL()).grid(row=i+1, column=0, padx=10, pady=10)
self.button1 = tk.Button(self, text = " Done ",
command=lambda: [page1.enter_freqs(), self.quitALL()])
self.unbind_all('<Return>') # work
self.bind('<Return>', (lambda a: [page1.enter_freqs(), self.quitALL()])) # work
# self.button1.bind('<Return>', (lambda a: [page1.enter_freqs(), self.quitALL()])) #doesn't work
self.button1.grid(row=i+1, column=1, padx=10, pady=10)
frame.tkraise()
except:
frame.tkraise()
def get_page(self, page_class):
return self.frames[page_class]
def quitALL(self):
self.destroy()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
self.text = tk.Text(self, bg='gray93', bd=0, height=1, width=30, font=('Helvetica', 14))
self.text.insert(tk.INSERT, "Please enter number of frequencies:")
self.text.grid(padx=10, pady=10)
entry = tk.Entry(self, textvariable=self.controller.shared_data["number_of_frequencies"])
entry.grid(padx=10)
self.controller.bind('<Return>', (lambda a: controller.show_frame(PageOne))) # work
self.button = tk.Button(self, text=" Done ",
command=lambda: controller.show_frame(PageOne))
# self.button.bind('<Return>', (lambda a: controller.show_frame(PageOne))) # doesn't work
self.button.grid(padx=10, pady=10)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
self.freq_list = self.controller.shared_data["frequencies"]
self.freq_list_int = []
def enter_freqs(self):
for freq in self.freq_list:
self.freq_list_int.append(int(freq.get()))
self.func(self.freq_list_int)
def func(self, freq_list):
print('some stuff')
if __name__ == "__main__":
app = Page()
app.mainloop()

Making a login page using tkinter in python

I'm trying to load a new frame when the user presses the login button as long as the details entered are correct. I've included print commands within the LogInCheck function in order to see if the code is executing correctly, which it is. My only problem is that it wont change the frame. I get the error 'LogIn' object missing attribute 'show_frame'
from tkinter import *
from tkinter import ttk
import tkinter as tk
LARGE_FONT= ("Arial", 16)
SMALL_FONT= ("Arial", 12)
current_tariff = None
def tariff_A():
global current_tariff
current_tariff= "A"
def tariff_B():
global current_tariff
current_tariff= "B"
def tariff_C():
global current_tariff
current_tariff= "C"
class PhoneCompany(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, PageThree, PageFour, PageFive, LogIn):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(LogIn)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
Thats my main class and this is the login page class:
class LogIn(tk.Frame):
def LogInCheck(self):
global actEntry
global pinEntry
act = "james"
pin = "Python123"
actNum = actEntry.get()
pinNum = pinEntry.get()
print("FUNCTION RUN")
if actNum == act and pinNum == pin:
print("CORRECT")
self.show_frame(StartPage)
elif actNum != act or pinNum != pin:
print("INCORRECT")
self.show_frame(LogIn)
def __init__(self, parent, controller):
global actEntry
global pinEntry
self.controller = controller
tk.Frame.__init__(self, parent)
logLabel = ttk.Label(self, text = "Login With Your Username and
Password", font = LARGE_FONT)
logLabel.pack(side = TOP, anchor = N, expand = YES)
actLabel = Label(self, text = 'Username:')
actEntry = Entry(self)
pinLabel = Label(self, text = 'Password: ')
pinEntry = Entry(self, show ="*")
actLabel.pack(pady =10, padx = 10, side = TOP, anchor = N)
pinLabel.pack(pady =5, padx = 10, side = TOP, anchor = S)
actEntry.pack(pady =10, padx = 10, side = TOP, anchor = N)
pinEntry.pack(pady =5, padx = 10, side = TOP, anchor = S)
logInButton = tk.Button(self, text = "Login",
command = self.LogInCheck)
logInButton.pack(side = TOP, anchor = S)
quitButton = tk.Button(self, text = "Quit", command = quit)
quitButton.pack(side = BOTTOM, anchor = S)
if __name__ == "__main__":
app = PhoneCompany()
app.mainloop()
I'll include my full code if you need to look at the rest of it:
from tkinter import *
from tkinter import ttk
import tkinter as tk
LARGE_FONT= ("Arial", 16)
SMALL_FONT= ("Arial", 12)
current_tariff = None
def tariff_A():
global current_tariff
current_tariff= "A"
def tariff_B():
global current_tariff
current_tariff= "B"
def tariff_C():
global current_tariff
current_tariff= "C"
class PhoneCompany(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, PageThree, PageFour, PageFive, LogIn):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(LogIn)
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="MENU", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button = tk.Button(self, text="View Account Balance",
command=lambda: controller.show_frame(PageOne))
button.pack()
button2 = tk.Button(self, text="Display Current Tariff",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
button3 = tk.Button(self, text="View List of Rates",
command=lambda: controller.show_frame(PageThree))
button3.pack()
button4 = tk.Button(self, text="View Latest Bill",
command=lambda: controller.show_frame(PageFour))
button4.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Account Balance", font=LARGE_FONT)
label.pack(pady=10,padx=10)
sublabel = tk.Label(self, text="Your current account balance is £230", font=SMALL_FONT)
sublabel.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Menu",
command=lambda: controller.show_frame(StartPage))
button1.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
global current_tariff
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Current Tariff", font=LARGE_FONT)
label.pack(pady=10,padx=10)
sublabel = tk.Label(self, text="Your current tariff is "+str(current_tariff), font=SMALL_FONT)
sublabel.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Change Tariff",
command=lambda: controller.show_frame(PageFive))
button1.pack()
button2 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button2.pack()
class PageThree(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Tariff Rates", font=LARGE_FONT)
label.pack(pady=10,padx=10)
sublabel = tk.Label(self, text="Peak Rates: A: £0.30 | B: £0.10 | C: £0.90", anchor="w", font=SMALL_FONT)
sublabel.pack(pady=10,padx=10)
sublabel2 = tk.Label(self, text="Off Peak: A: £0.05 | B: £0.02 | C: -", anchor="w", font=SMALL_FONT)
sublabel2.pack(pady=10,padx=10)
sublabel3 = tk.Label(self, text="Line Rental: A: £15.00 | B: £20.00 | C: £30.00", anchor="w", font=SMALL_FONT)
sublabel3.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
class PageFour(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Latest Bill", 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 PageFive(tk.Frame):
def __init__(self, parent, controller):
global current_tariff
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Change Tariff", font=LARGE_FONT)
label.pack(pady=10,padx=10)
sublabel = tk.Label(self, text="Select new tariff\nView list of tariff rates on the main menu to see the prices.", font=SMALL_FONT)
sublabel.pack(pady=10,padx=10)
button1 = tk.Button(self, text="A",
command=lambda:[controller.show_frame(StartPage),tariff_A])
button1.pack()
button2 = tk.Button(self, text="B",
command=lambda:[controller.show_frame(StartPage),tariff_B])
button2.pack()
button3 = tk.Button(self, text="C",
command=lambda:[controller.show_frame(StartPage),tariff_C])
button3.pack()
button4 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button4.pack()
class LogIn(tk.Frame):
def LogInCheck(self):
global actEntry
global pinEntry
act = "james"
pin = "Python123"
actNum = actEntry.get()
pinNum = pinEntry.get()
print("FUNCTION RUN")
if actNum == act and pinNum == pin:
print("CORRECT")
self.show_frame(StartPage)
elif actNum != act or pinNum != pin:
print("INCORRECT")
self.show_frame(LogIn)
def __init__(self, parent, controller):
global actEntry
global pinEntry
self.controller = controller
tk.Frame.__init__(self, parent)
logLabel = ttk.Label(self, text = "Login With Your Username and Password", font = LARGE_FONT)
logLabel.pack(side = TOP, anchor = N, expand = YES)
actLabel = Label(self, text = 'Username:')
actEntry = Entry(self)
pinLabel = Label(self, text = 'Password: ')
pinEntry = Entry(self, show ="*")
actLabel.pack(pady =10, padx = 10, side = TOP, anchor = N)
pinLabel.pack(pady =5, padx = 10, side = TOP, anchor = S)
actEntry.pack(pady =10, padx = 10, side = TOP, anchor = N)
pinEntry.pack(pady =5, padx = 10, side = TOP, anchor = S)
# runs the 'LoginCheck' function
logInButton = tk.Button(self, text = "Login",
command = self.LogInCheck)
logInButton.pack(side = TOP, anchor = S)
quitButton = tk.Button(self, text = "Quit", command = quit)
quitButton.pack(side = BOTTOM, anchor = S)
if __name__ == "__main__":
app = PhoneCompany()
app.mainloop()
I know it's quite messy and there may be other errors, but for now i just need to figure out why it wont change the frame after successfully logging in.
It needs to be self.controller.show_frame(StartPage).

Categories