Search code examples
pythonpython-3.xtkinterdestroy

Why does destroy() not work in this code?


This is a simple test script I am attempting to write which will help me teach myself about tkinter...

from tkinter import *
def hello():
   print("U pressed it lol")

global window1, window2
window2 = None
window1 = None

def setWindow(windowEnter):
   global window
   window = windowEnter
   window = Tk()
   window.attributes("-fullscreen", True)

def newScreen(newScreen, screenToDelete):
   setWindow(newScreen)
   print("New Window Created")
   screenToDelete.destroy()
   print("He ded lol")

setWindow(window1)

def setStuff():
   button = Button(window1, text="hey", command=hello)
   label = Label(window1, text="YoYoYo My dude")
   button2 = Button(window1, text="Next Page", command = lambda: newScreen(window2, window1))

   button.pack()
   label.pack()
   button2.pack()

setStuff()

When I run this code it returns an error?

File "C:\Users\026341\Desktop\test.py", line 19, in newScreen
screenToDelete.destroy()
AttributeError: 'NoneType' object has no attribute 'destroy'

Why doesn't this work & how do i fix it?

Thanks in advance :) (Btw I'm using python 3.6)


Solution

  • You set

    window2 = None
    window1 = None
    

    as global variables and then define the command function for button2 to be

    lambda: newScreen(window2, window1)
    

    Which calls newScreen with the values window2 and window1 which are both None, hence the error. The underlying issue here is your setWindow function:

    def setWindow(windowEnter):
        global window
        window = windowEnter
        window = Tk()
        window.attributes("-fullscreen", True)
    

    which doesn't work the way you are using it. When you call setWindow(window1), you pass the value of window1, what the function does with the variable cannot be seen on a global scope. A quick example would be this:

    def increment(a):
        a +=1
    x = 1
    print(x)
    increment(x)
    print(x)
    

    which will print 1 twice.

    To achieve what you want I suggest you use a dictionary to keep track of your windows.

    from tkinter import *
    def hello():
       print("U pressed it lol")
    
    global window1, window2
    windows = {}
    
    
    def setWindow(window_name):
       windows[window_name] = Tk()
       windows[window_name].attributes("-fullscreen", True)
    
    def newScreen(newScreen_name, screenToDelete_name):
       setWindow(newScreen_name)
       print("New Window Created")
       windows[screenToDelete_name].destroy()
       del windows[screenToDelete_name] #delete invalid entry from dict
       print("He ded lol")
    
    setWindow("window1")
    
    def setStuff():
       button = Button(windows["window1"], text="hey", command=hello)
       label = Label(windows["window1"], text="YoYoYo My dude")
       button2 = Button(windows["window1"], text="Next Page", command = lambda: newScreen("window2", "window1"))
    
       button.pack()
       label.pack()
       button2.pack()
    
    setStuff()
    

    Note on the side: previously your function was def newScreen(newScreen, screenToDelete), which is very confusing/bad style since both the function and its first argument share the same name. I changed it anyway to highlight that it now takes strings as arguments, but keep it in mind for the furture.