Home > Software engineering >  How to change Label according to user input in tkinter app?
How to change Label according to user input in tkinter app?

Time:10-03

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()
  • Related