Prevent multiple toplevels from opening?

Question:

I have a object oriented tkinter program set up.
I have initialized a variable to store Toplevel() in as

self.toplevel = None

Then when I create the actual Toplevel window I simply assign it to the variable:

self.toplevel = Toplevel()

The thing is…when the Toplevel() window is closed, the value still remains in the variable self.toplevel. How can I reset the variable back to None after closing the window so that I can perform a check:

if (self.toplevel == None):
    self.toplevel = Toplevel()

Or are there any other methods to prevent multiple Toplevel Windows from opening?

Answers:

Check this How do I handle the window close event in Tkinter?

Assign the value None to self.toplevel after the Toplevelcloses usign a callback function TopCloses. For this, write a method within the GUI class to access the toplevel attribute and set it’s value to None inside the callback function.

In your main program,

def TopCloses():
    top.destroy()
    #Call the setTopLevel method and assign the attribute toplevel value None
    guiObject.setTopLevel(None)

top.protocol("WM_DELETE_WINDOW", TopCloses)
root.mainloop()

Here is my solution:

#somewhere in __init__ make
self.window = None
#I took this piece of code from my bigger app and I have a function 
#self.makevariables(), which is called in init, which contains the line above.
def instructions(self):      
    if self.window == None: #here I check whether it exists, if not make it, else give focus to ok button which can close it
        self.window = Toplevel(takefocus = True)
        #some optional options lol
        self.window.geometry("200x200")
        self.window.resizable(0, 0)
        #widgets in the toplevel
        Label(self.window, text = "NOPE").pack() 
        self.window.protocol("WM_DELETE_WINDOW", self.windowclosed) #this overrides the default behavior when you press the X in windows and calls a function
        self.okbutton = Button(self.window, text = "Ok", command = self.windowclosed, padx = 25, pady = 5)
        self.okbutton.pack()
        self.okbutton.focus()
        self.okbutton.bind("<Return>", lambda event = None:self.windowclosed())
    else:
        self.okbutton.focus()  #You dont need to give focus to a widget in the TopLevel, you can give the focus to the TopLevel, depending how you want it
       #self.window.focus() works too    
def windowclosed(self): #function to call when TopLevel is removed
    self.window.destroy()
    self.window = None
Answered By: Jozef Méry

These are all overly complicated solutions imo.

I just use win32gui as such:

toplevel_hwid = win32gui.FindWindow(None, '<Top Level Window Title>')

if toplevel_hwid:
    print(f'Top level window already open with HWID: {toplevel_hwid}')
    win32gui.SetForegroundWindow(toplevel_hwid)
    return
else:
    <create new top level>

Simple, easy, and gives you the flexibility to close, move, focus, etc.

Answered By: Klh
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.