0

I am trying to make an instant messenger with multiple frames and have incorporated some code from a tutorial I have been following. My entry "e" is supposed to save the user input in a text file and display it in a text box however when I call e.get() I get the following error. It is treating e as an attribute instead of an object (I think) and I don't know why.

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Douglas Rouse\AppData\Local\Programs\Python\Python35-32\lib\idlelib\run.py", line 119, in main
    seq, request = rpc.request_queue.get(block=True, timeout=0.05)
  File "C:\Users\Douglas Rouse\AppData\Local\Programs\Python\Python35-32\lib\queue.py", line 172, in get
    raise Empty
queue.Empty

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Douglas Rouse\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1550, in __call__
    return self.func(*args)
  File "C:\Users\Douglas Rouse\Google Drive\Python\New structure.py", line 78, in callback
    f.write("Douglas:"+self.e.get()+"\n")
AttributeError: 'PageOne' object has no attribute 'e'

I can't tell why it thinks e is an attribute or why it can't call e (the entry) as an object and not the class itself. Here is the code I am working on. the error is in the callback function.

import tkinter as tk
LARGE_FONT=("Verdana", 12)


class SeaofBTCapp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)

        container.grid()

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        frame = StartPage(container, self)
        frame_ = PageOne(container, self)

        self.frames[StartPage] = frame
        self.frames[PageOne] = frame_

        frame.grid(row=0, column=0, sticky="nsew")
        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,*args):
        tk.Frame.__init__(self, parent)
        usrlabel = tk.Label(self, text="Input Username", font=LARGE_FONT)
        usrlabel.grid(pady=10,padx=10)
        usrentry = tk.Entry(self)
        #usrentry.grid()
        global uu
        uu = usrentry.get()

        #command within button cant throw args to funcs. Use lambda to throw those args to the func instead
        button1 = tk.Button(self, text="Visit Page 1",command=
                            lambda: controller.show_frame(PageOne))
        button1.grid()

class PageOne(tk.Frame):

    def __init__(self, parent, controller):

        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page 1", font=LARGE_FONT)
        label.grid()

        #command within button cant throw args to funcs. Use lambda to throw those args to the func instead
        button1 = tk.Button(self, text="Start Page",command=lambda:controller.show_frame(StartPage))
        button1.grid()

        file = open("htfl.txt","r") #opens file
        #print(file.read(1))
        a = file.read()
        b = file.read()
        print(file.read())

        #entry
        e = tk.Entry(self,width= 40)
        e.grid(row=10,column=0,sticky = "W")
        #text
        T = tk.Text(self, height=9, width=30)
        T.grid(row=3,column= 0)
        #T.insert(END,a)
        b = tk.Button(self, text="Send", width=10, command=self.callback).grid(row=10,column=2)

    def callback(self,*args):
        f = open("htfl.txt","a")
        f.write("Douglas:"+self.e.get()+"\n")
        e.delete(0, 'end')
        #print (e.get())
        #Button



app = SeaofBTCapp()
douglas rouse
  • 148
  • 1
  • 2
  • 15

1 Answers1

1

The e you're creating in PageOne's __init__ method is a local variable and can't be referenced from the outside. What you want to do is to make e an attribute of your object. This will result in

self.e = tk.Entry(self,width= 40)

If you now want to access this attribute in your object, use self.e instead of e.

self.e.grid(row=10,column=0,sticky = "W")
# -skipped-
f.write("Douglas:"+self.e.get()+"\n")
# -skipped-
self.e.delete(0, 'end')
TidB
  • 1,749
  • 1
  • 12
  • 14
  • 2
    I think this answer would be better if the example showed the use of `self.e` rather than burying the change in the following sentence. – Bryan Oakley Feb 16 '17 at 13:44
  • @TidB I'm not quite sure I understand. I tried accessing it with self e.write("Douglas:"+self.e.get()+"\n") – douglas rouse Feb 16 '17 at 14:38
  • @douglasrouse Why are you now trying `self.e.write(...)` instead as previously `f.write(...)`? The version with `f` was fine. – TidB Feb 16 '17 at 14:47
  • @TidB yeah sorry my mistake I didn't change that. its still f.write(self.e.get()) I meant to ask what you meant with make it an attribute of my object. – douglas rouse Feb 16 '17 at 15:12
  • @douglasrouse It seems that you don't know too much about classes and objects yet, so I'd suggest you reading [this question](https://stackoverflow.com/questions/2709821/what-is-the-purpose-of-self), or basically any Python tutorial that involves classes. – TidB Feb 16 '17 at 15:16
  • @TidB yeah, you are right. I am in the process of learning about classes. The way I understood it is that you want me to take the e= ... out of the init and make it a class object however when I do that the entry feild is its own separate window. Sorry for all the dumb questions and thank you for taking the time to answer them! – douglas rouse Feb 16 '17 at 16:16