Search code examples
pythonpython-3.xooptkinter

How to refer globally to a object created in a function?


I'm trying to program a GUI in tkinter that sets the root to a "darkmode" waits a specific amount of time and then closing or withdrawing itself and at the same moment a new Toplevel should be generated. The withdrawed main window should pop up again after I closed the Toplevel. Therefore I used the if statement, but I get a NameError: newWindow not defined, evenhough I set it to global.

This my code:

from tkinter import *

def answer(event):
    AnsLabel["text"]="You clicked the Button!"

def darkmode(event):
    Hallo["fg"]="white"
    Hallo["bg"]="black"
    main["bg"]="black"
    AnsLabel["bg"]="black"
    AnsLabel["fg"]="white"
    button["bg"]="black"
    button["fg"]="white"
    main.after(3000,createWindow)

def createWindow():
    global newWindow
    newWindow=Toplevel()
    newLabel=Label(newWindow,text="You found the secret function!")
    newLabel.pack()
    main.withdraw()

main=Tk()
Hallo=Label(main,text="Hello")
button=Button(main,text="BUTTON")
button.bind("<Button-1>",answer)
button.bind("<Button-3>",darkmode)
AnsLabel=Label(main,text="Hello!")
Hallo.pack()
button.pack()
AnsLabel.pack()
if not newWindow.winfo_exists():
    main.deiconify()
main.mainloop()

Solution

  • Here you go. The issue with your code is that it runs the if statement then the Tkinter mainloop. in order to get your code to work you need to bind a function.

    from tkinter import *
    
    def answer(event):
        AnsLabel["text"]="You clicked the Button!"
    
    def darkmode(event):
        Hallo["fg"]="white"
        Hallo["bg"]="black"
        main["bg"]="black"
        AnsLabel["bg"]="black"
        AnsLabel["fg"]="white"
        button["bg"]="black"
        button["fg"]="white"
        main.after(3000,createWindow)
    
    def createWindow():
        global newWindow
        newWindow=Toplevel()
        newLabel=Label(newWindow,text="You found the secret function!")
        newLabel.pack()
        main.withdraw()
        newWindow.bind(sequence="<Destroy>", func=lambda x: main.deiconify())
        
    
    main=Tk()
    Hallo=Label(main,text="Hello")
    button=Button(main,text="BUTTON")
    button.bind("<Button-1>",answer)
    button.bind("<Button-3>",darkmode)
    AnsLabel=Label(main,text="Hello!")
    Hallo.pack()
    button.pack()
    AnsLabel.pack()
    
    
    
    main.mainloop()
    

    The code I changed is here.

    def createWindow():
        global newWindow
        newWindow=Toplevel()
        newLabel=Label(newWindow,text="You found the secret function!")
        newLabel.pack()
        main.withdraw()
        newWindow.bind(sequence="<Destroy>", func=lambda x: main.deiconify())
    

    its easier and cleaner to use classes

    from tkinter import *
    
    class App(Tk):
    
        def __init__(self) -> None:
            super().__init__()
    
            self.hallo=Label(self,text="Hello")
            self.button=Button(self,text="BUTTON")
            self.button.bind("<Button-1>",self.answer)
            self.button.bind("<Button-3>",self.darkmode)
            self.ansLabel=Label(self,text="Hello!")
            self.hallo.pack()
            self.button.pack()
            self.ansLabel.pack()
    
        def answer(self, event):
            self.ansLabel["text"]="You clicked the Button!"
    
        def darkmode(self, event) -> None:
    
            self.hallo["fg"]="white"
            self.hallo["bg"]="black"
            self["bg"]="black"
            self.ansLabel["bg"]="black"
            self.ansLabel["fg"]="white"
            self.button["bg"]="black"
            self.button["fg"]="white"
            self.after(3000,self.createWindow)
    
        def createWindow(self):
            global newWindow
            newWindow=Toplevel()
            newLabel=Label(newWindow,text="You found the secret function!")
            newLabel.pack()
            self.withdraw()
            newWindow.bind(sequence="<Destroy>", func=self.reopen)
    
        def reopen(self, event):
    
            self.deiconify()
        
    
    if __name__ == "__main__":
        app = App()
        app.mainloop()