Search code examples
pythonclasstkintertkinter-entry

How to use the tkinter Entry widget?


I'm trying to insert an Entry field in my tkinter-based GUI. It has three different "pages" as classes with buttons etc, but the Entry field doesn't work.

I want to put the entry field in the last page (class PageTwo). Then I just want to click one of the check buttons and I would be OK if the entered text would show as print, or in another text field in the GUI. Update: I changed the entry code to controller.wordde = Entry(self) and made a button print(controller.wordde.get())

The error code I get is:

Traceback (most recent call last):
  File "C:\x\g_4.py", line 147, in <module>
    app = SeaofBTCapp()
  File "C:\x\g_4.py", line 40, in __init__
    frame = F(container, self)
  File "C:\x\g_4.py", line 141, in __init__
    wordde.grid(row=3, column=1)
NameError: name 'wordde' is not defined

This is the code:

from tkinter import *
import tkinter as tk
import csv
import random
import sys

z = random.randint(1,50)
with open('vokabelnsemicolon.csv') as csvfile:
    readCSV = csv.reader(csvfile, delimiter=';')
    delist = []
    enlist = []
    for row in readCSV:
        eng = row[1]
        deu = row[0]

        delist.append(deu)
        enlist.append(eng)

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


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="German -> English",
                            command=lambda: controller.show_frame(PageOne))
        button.pack()

        button2 = tk.Button(self, text="-> English -> German",
                            command=lambda: controller.show_frame(PageTwo))
        button2.pack()



#German -> English
class PageOne(tk.Frame):


    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="German -> English", font=LARGE_FONT)
        label.grid(row=0, column=0)

        button1 = tk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.grid(row=1, column=1)

        button2 = tk.Button(self, text="English -> German",
                            command=lambda: controller.show_frame(PageTwo))
        button2.grid(row=2, column=1)

        button3 = tk.Button(self, text="Check",
                            command=None)
        button3.grid(row=4, column=1)

        #text field for entry box
        Label(self, text='"'+enlist[z]+'"'+ ' in english is: ').grid(row=3, column=0)

        #entry field
        worden = Entry(self)
        worden.grid(row=3, column=1)


#English -> German
class PageTwo(tk.Frame):


    def checkybutton(self):
        print('checkbutton!')  

    def checkybutton2(self):
        print(controller.wordde.get())

    def __init__(self, parent, controller):

        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="English -> German", font=LARGE_FONT)
        label.grid(row=0, column=0)

        button1 = tk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.grid(row=1, column=1)

        button2 = tk.Button(self, text="German -> English",
                            command=lambda: controller.show_frame(PageOne))
        button2.grid(row=2, column=1)
        #text field for entry box
        Label(self, text='"'+delist[z]+'"'+ ' in german is: ').grid(row=3, column=0)


        button3 = tk.Button(self, text="checkbutton",
                            command=self.checkybutton)
        button3.grid(row=4, column=1)


        button4 = tk.Button(self, text="checkbutton 2",
                            command=self.checkybutton2)
        button4.grid(row=4, column=0)


        #entry field
        controller.wordde = Entry(self)

        wordde.grid(row=3, column=1)

        txt = Text(self, width=35, height=1, wrap=WORD)
        txt.grid(row=5, columnspan=2, sticky=W)    


app = SeaofBTCapp()
app.mainloop()

Solution

  • You have to store the entry somewhere, to be able to refer to it later.

    For your code, it seems the best place to store it is in the controller, as it is accessible on all pages:

    instead of worden = Entry(self) use:

    controller.worden = Entry(self)
    

    That will store a reference to your entry instance in the controller object. Later you can use controller.worden.get() to retrieve the value:

    print(controller.worden.get())
    

    EDIT: To clarify - controller is an instance of the SeaofBTCapp class created here:

    app = SeaofBTCapp()
    

    That instance is passed to the other classes' __init__ here:

    for F in (StartPage, PageOne, PageTwo):
        frame = F(container, self)  # self is the controller
    

    Now, since you will need access to the controller in other methods that are not __init__, you have to also store a reference to the controller in the instances of those classes.

    Change __init__ in the StartPage, PageOne and PageTwo classes to do this:

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        #.... rest of the method here ...
    

    That means each page istance has a reference to the controller stored as an attribute. Now, in the methods of those classes that are not __init__, you can access that object by using self.controller:

    def checkybutton2(self):
        print(self.controller.wordde.get())