djohnson129
djohnson129

Reputation: 15

Tkinter .destroy() button causes error when in function

I have a button in my Tkinter window that, when clicked, needs to call two functions: a .get() to store the entry box value and a .destroy() so the window closes when button is pressed.

I must be doing something wrong because whether I put the .destroy() in my grouped function with .get() or put .destroy() as the sole command in the button, I get this error:

AttributeError: 'GuardianLocator' object has no attribute 'frame'

I believe my code is near identical to other answers on this site so I'm not sure why .destroy() isn't working...

from tkinter import *


class GuardianLocator:

    def __init__(self, master):
        self._name = ""
        frame = Frame(master)
        frame.grid()
        master.title("GUARDIAN LOCATOR")

        self.locator_label = Label(frame, text="Which Sailor Guardian are you looking for?", width=40, height=2)
        self.locator_label.grid()

        self.entry = Entry(frame)
        self.entry.grid()

        self.button1 = Button(frame, text="Search", command=self.guardian_name, pady=2)
        self.button1.grid()


    def guardian_name(self):
        self._name = self.entry.get()
        self.frame.destroy()
        return self.entry.get()

EDIT

When I make the recommended changes to the self.frame from the answers, the program runs, but then when I click the button I get this error-

Traceback (most recent call last):
  File "C:\Python34\lib\tkinter\__init__.py", line 1482, in __call__
    return self.func(*args)
  File "C:\Users\david\PycharmProjects\Sailor Moon Hunt\guardian_locator.py", line 25, in guardian_name
    return self.entry.get()
  File "C:\Python34\lib\tkinter\__init__.py", line 2484, in get
    return self.tk.call(self._w, 'get')
_tkinter.TclError: invalid command name ".45213328.45795632"

It appears to be referring to the .get() call, but that was working fine before I made the self.frame changes. Does anyone know what that error means?

Upvotes: 0

Views: 2381

Answers (2)

user2555451
user2555451

Reputation:

The problem isn't with the destroy method. Instead, Python is complaining that it cannot find the frame attribute of self. This is because you forgot to actually make frame an instance attribute inside GuardianLocator.__init__:

self.frame = Frame(master)
self.frame.grid()

Notice the self. placed before each use of the name frame.

Without doing this, the name frame is local to the __init__ method and therefore inaccessible inside guardian_name via self.


Edit:

When you do:

self.frame.destroy()

the Frame object referenced by self.frame is destroyed and becomes no longer usable. Moreover, the Entry object referenced by self.entry is likewise destroyed since it is a child of the frame. This means that you cannot do:

return self.entry.get()

because self.entry no longer exists at that point.

To avoid this problem, you should be returning self._name, which equals self.entry.get():

return self._name

Upvotes: 2

Shahzad
Shahzad

Reputation: 2063

change this code:

def __init__(self, master):
    self._name = ""
    frame = Frame(master)
    frame.grid()
    master.title("GUARDIAN LOCATOR")

with the following:

def __init__(self, master):
    self._name = ""
    self.frame = Frame(master)
    self.frame.grid()
    master.title("GUARDIAN LOCATOR")

Upvotes: 0

Related Questions