I am creating a planning app and I want it to be personalized by having a title that says [Name]'s Planner. The user can enter their name into a text entry widget, press Submit, and then it will be displayed in the label. My application also has multiple pages, so the text entry will be on the start page and the label will be on the home page.
I have named the text entry widget nameentry
and have created a function that takes the data from nameentry
and displays it in the label name_label
, however, I am getting an error message when I try to call the function by clicking the Submit button which says NameError: name 'nameentry' is not defined
.
I am confused as I believe I have already defined nameentry
by saying it equals the text entry widget.
import calendar
import tkinter as tk
from tkinter import ttk
from tkcalendar import *
from datetime import datetime
#calendar and display in label
#window = Tk()
#window.title("StudyFriendO")
LARGE_FONT= ("Verdana", 24)
class StudyFriendO(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("StudyFriendO") #naming window title
self.geometry('850x830') #size of window
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, HomePage, ToDoPage, TimetablePage): #list of multiple frames of program
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()
def set_date(self, cont):
#frame: StartPage = self.frames[cont]
#frame.date_label.config(text="Today's date is " datetime.today().strftime("%B %d, %Y")) #function to get date from
frame2: HomePage = self.frames[HomePage]
frame2.date_label.config(text= datetime.today().strftime("%B %d, %Y")) #function to get date from
def getname(self, cont): #FUNCTION WHICH GRABS NAME FROM TEXT ENTRY
frame2: HomePage = self.frames[HomePage]
frame2.name_label.configure(text=nameentry.get() "'s Planner ")
class StartPage(tk.Frame): #creating start page
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="StudyFriendO", font = LARGE_FONT, bg="#f2fcff")
label.pack(fill="x")
#place(x=315,y=100)
photo1 = tk.PhotoImage(file='apple.png') #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo1)
panel.image = photo1
panel.pack(fill="x")
#place(x=270,y=150)
label2 = tk.Label(self, text="Enter today's date and your first name below:", bg="#f2fcff")
label2.pack(fill="x", ipady=20)
#place(x=305, y=400)
cal = Calendar(self, background="#e0f6fc", disabledbackground="white", bordercolor="light blue", headersbackground="light blue", normalbackground="#e0f6fc", foreground="black", normalforeground='black', headersforeground='white', selectmode="day", year=2021, month=8, day=9)
cal.place(relx=0.5, rely=0.5, anchor='center')
#(x=300,y=430) #calendar
#TEXT ENTRY WHERE PERSON INPUTS NAME
nameentry = tk.Entry(self, width=20, bg="white") #text input for users name
nameentry.place(relx=0.5, rely=0.68, anchor='center')
#(x=365, y=635)
caldate = ttk.Button(self, text="Submit",
command=lambda: controller.set_date(StartPage)) #button to get current date
caldate.place(relx=0.5, rely=0.63, anchor='center')
button1 = ttk.Button(self, text="Enter",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(relx=0.5, rely=0.73, anchor='center')
#(x=387,y=660)
#BUTTON WHICH CALLS FUNCTION WHICH GRABS NAME (CURRENTLY LOCATED IN WEIRD LOCATION)
namebutton = ttk.Button(self, text="Submit", command=lambda: controller.getname(StartPage))
namebutton.place(relx=0.5, y=60)
#self.date_label = tk.Label(self, text="") #label to display date
#self.date_label.pack(pady=20)
self.configure(bg='#f2fcff')
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#label = tk.Label(self, text="Home", font = LARGE_FONT)
#label.pack(pady=10,padx=10)
#width of x
frame = tk.Frame(self, bg="#c0e3ed", height=110)
frame.pack(fill="x")
#LABEL WHICH DISPLAYS NAME FROM TEXT ENTRY
#tk.Label(self, text ="Name's Planner", fg="white", bg="#c0e3ed", font = LARGE_FONT).place(relx=0.5, y=50, anchor='center')
self.name_label = tk.Label(self, text="", font=("Arial Bold", 50))
self.name_label.place(x=0, y=0)
self.date_label = tk.Label(self, text="", bg="#c0e3ed")
# keep placing the label at top right corner
self.date_label.place(relx=1, y=0, anchor='ne')
#pack(side='top', anchor='ne')
#height of Y
tk.Label(self, text="", fg="white", bg="#99cbd8").pack(side="left", fill="y", ipadx=73)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Home", command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(x=35, y=145)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="To Do", command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.place(x=35, y=225)
#(relx=0.2, rely=0.4, anchor='center')
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Timetable", command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.place(x=35, y=305)
photo2 = tk.PhotoImage(file='apple.png') #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo2)
panel.image = photo2
panel.place(x=35, y=400)
self.configure(bg='#f7f6f6')
class ToDoPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="To Do", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
class TimetablePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Timetable", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
app = StudyFriendO()
app.mainloop()
CodePudding user response:
The problem is happening because you're trying to reference a variable that's local to one method of one page on another. In an app with this architecture, a good way to share data among the Page class instances is through the controller
argument they are all passed when they're created, which in this case is the StudyFriendO
class instance.
Since you may have more than one variable to share as you develop your app, I've added a shared_data
dictionary attribute and initialized with a tk.StringVar
associated with the key 'name'
. It is used as the textvariable=
option when creating the tk.Entry
widget on the StartPage
and then also by the getname()
method of the StudyFriendO
controller. Using a StringVar
allows the dictionary item to be defined before the Entry
widget using it is created. After that happens (i.e. the StartPage
instance is created) the current value of the Entry
can be retrieved indirectly through it instead of the widget itself in the getname()
method. You can easily add more variables in the future should you need them.
Below is your code with the modifications described. I've indicated where the changes are with ####
comments to make them standout.
import calendar
import tkinter as tk
from tkinter import ttk
from tkcalendar import *
from datetime import datetime
#calendar and display in label
#window = Tk()
#window.title("StudyFriendO")
IMAGE_PATH = 'apple.png'
LARGE_FONT= ("Verdana", 24)
class StudyFriendO(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("StudyFriendO") #naming window title
self.geometry('850x830') #size of window
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
#### ADDED
self.shared_data = { # Variables shared by all pages.
'name': tk.StringVar(value='')
}
self.frames = {}
for F in (StartPage, HomePage, ToDoPage, TimetablePage): #list of multiple frames of program
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()
def set_date(self, cont):
#frame: StartPage = self.frames[cont]
#frame.date_label.config(text="Today's date is " datetime.today().strftime("%B %d, %Y")) #function to get date from
frame2: HomePage = self.frames[HomePage]
frame2.date_label.config(text= datetime.today().strftime("%B %d, %Y")) #function to get date from
def getname(self, cont): #FUNCTION WHICH GRABS NAME FROM TEXT ENTRY
frame2: HomePage = self.frames[HomePage]
#### frame2.name_label.configure(text=nameentry.get() "'s Planner ")
frame2.name_label.configure(text=self.shared_data['name'].get() "'s Planner ")
class StartPage(tk.Frame): #creating start page
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="StudyFriendO", font = LARGE_FONT, bg="#f2fcff")
label.pack(fill="x")
#place(x=315,y=100)
photo1 = tk.PhotoImage(file=IMAGE_PATH) #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo1)
panel.image = photo1
panel.pack(fill="x")
#place(x=270,y=150)
label2 = tk.Label(self, text="Enter today's date and your first name below:", bg="#f2fcff")
label2.pack(fill="x", ipady=20)
#place(x=305, y=400)
cal = Calendar(self, background="#e0f6fc", disabledbackground="white", bordercolor="light blue", headersbackground="light blue", normalbackground="#e0f6fc", foreground="black", normalforeground='black', headersforeground='white', selectmode="day", year=2021, month=8, day=9)
cal.place(relx=0.5, rely=0.5, anchor='center')
#(x=300,y=430) #calendar
#TEXT ENTRY WHERE PERSON INPUTS NAME
#### nameentry = tk.Entry(self, width=20, bg="white") #text input for users name
nameentry = tk.Entry(self, width=20, bg="white", #text input for users name
textvariable=controller.shared_data['name'])
nameentry.place(relx=0.5, rely=0.68, anchor='center')
#(x=365, y=635)
caldate = ttk.Button(self, text="Submit",
command=lambda: controller.set_date(StartPage)) #button to get current date
caldate.place(relx=0.5, rely=0.63, anchor='center')
button1 = ttk.Button(self, text="Enter",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(relx=0.5, rely=0.73, anchor='center')
#(x=387,y=660)
#BUTTON WHICH CALLS FUNCTION WHICH GRABS NAME (CURRENTLY LOCATED IN WEIRD LOCATION)
namebutton = ttk.Button(self, text="Submit", command=lambda: controller.getname(StartPage))
namebutton.place(relx=0.5, y=60)
#self.date_label = tk.Label(self, text="") #label to display date
#self.date_label.pack(pady=20)
self.configure(bg='#f2fcff')
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#label = tk.Label(self, text="Home", font = LARGE_FONT)
#label.pack(pady=10,padx=10)
#width of x
frame = tk.Frame(self, bg="#c0e3ed", height=110)
frame.pack(fill="x")
#LABEL WHICH DISPLAYS NAME FROM TEXT ENTRY
#tk.Label(self, text ="Name's Planner", fg="white", bg="#c0e3ed", font = LARGE_FONT).place(relx=0.5, y=50, anchor='center')
self.name_label = tk.Label(self, text="", font=("Arial Bold", 50))
self.name_label.place(x=0, y=0)
self.date_label = tk.Label(self, text="", bg="#c0e3ed")
# keep placing the label at top right corner
self.date_label.place(relx=1, y=0, anchor='ne')
#pack(side='top', anchor='ne')
#height of Y
tk.Label(self, text="", fg="white", bg="#99cbd8").pack(side="left", fill="y", ipadx=73)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Home", command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(x=35, y=145)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="To Do", command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.place(x=35, y=225)
#(relx=0.2, rely=0.4, anchor='center')
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Timetable", command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.place(x=35, y=305)
photo2 = tk.PhotoImage(file=IMAGE_PATH) #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo2)
panel.image = photo2
panel.place(x=35, y=400)
self.configure(bg='#f7f6f6')
class ToDoPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="To Do", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
class TimetablePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Timetable", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
app = StudyFriendO()
app.mainloop()