Search code examples
pythontkinterspyder

Spyder not terminating tkinkter mainloop()


I am starting with python and I'm using Spyder 3.9.13 with Python 3.9

When beginning with the GUI design I have run in one problem: Spyder runs the script just once and jams in infinite loop.

Code that fails:

import tkinter as TK
ws=TK.Tk()
print('Foo')
ws.mainloop()
print('Bar')

When run from Spyder the window emerges and only the Foo is printed. When run from command line, the Bar is printed when the window is closed, as expected.

Adding the manloop killing button does not help either, the behaviour is the same.

import tkinter as TK
ws=TK.Tk()

Button(
    ws,
    text='Exit',
    command=lambda:ws.destroy()
).pack(expand=True)

print('Foo')
ws.mainloop()
print('Bar')

When the destroy() method call is replaced by quit() call the Bar is printed but the window is not closed.

The little expanded code works partially as intended:

import tkinter as TK

class FooBar:
    def __init__(self,Name):
    self.win=TK.Tk()
    self.win.title=(Name)

    def terminate(self):
        self.win.quit()
        self.win.destroy()

ws=FooBar('FooBar')

TK.Button(
    ws.win,
    text='Exit',
    command=lambda:ws.terminate()
).pack(expand=True)

print('Foo')
ws.win.mainloop()
print('Bar')

Even this code runs differently from the Spyder and from the command line. Form command line the Bar is printed no matter how the window is terminated; by the Exit button or the cross button. On the other hand, Spyder closes the window and prints Bar only if the window is closed by the Exit button. When closed as a window, the Bar is not printed and it is still stuck in the loop.

What causes this behaviour and how can I prevent it?


Solution

  • Please give this a try

    import tkinter as TK
    
    
    class FooBar:
        def __init__(self, name):
            self.win = TK.Tk()
            self.win.title = name
            self.win.protocol("WM_DELETE_WINDOW", self.terminate)
    
        def terminate(self):
            self.win.destroy()
    
    
    ws = FooBar('FooBar')
    
    TK.Button(
        ws.win,
        text='Exit',
        command=ws.terminate
    ).pack(expand=True)
    
    print('Foo')
    ws.win.mainloop()
    print('Bar')
    

    self.win.protocol("WM_DELETE_WINDOW", self.terminate) might help with this. self.win.destroy() should work but I don't have experience with Spyder to be sure about it.

    OP's EDIT:

    It seems it was the protocol("WM_DELETE_WINDOW") missing.

    import tkinter as TK
    
    ws=TK.Tk()
    ws.protocol("WM_DELETE_WINDOW", ws.destroy)
    
    TK.Button(
        ws,
        text='Exit',
        command=ws.destroy
    ).pack(expand=True)
    
    print('Foo')
    ws.mainloop()
    print('Bar')
    

    Now the Bar is printed after the window is closed, no matter how, when called from both Spyder and Command Line.