[Tkinter-discuss] Debugging non-zero exit code

Reinis Danne rei4dan at gmail.com
Sat Feb 6 15:22:38 EST 2016


On Sat, Feb 06, 2016 at 08:02:43PM +0100, Michael Lange wrote:
> Hi,
> 
> On Sat, 6 Feb 2016 18:43:07 +0200
> Reinis Danne <rei4dan at gmail.com> wrote:
> 
> (...)
> > Adding root.wm_protocol('WM_DELETE_WINDOW', root.quit) worked
> > indeed, but only for the close button. It didn't work if I closed
> > the window with Alt+F4 or File->Exit. On further inspection it
> > already used WM_DELETE_WINDOW protocol in
> > main.py::BKChem.initialize() like this:
> 
> That's odd, maybe the binding for Alt+F4 was overridden somewhere else
> in the code? And doesn't File->Exit call the same _quit() procedure as
> the one one linked to WM_DELETE_WINDOW?
> 
> (...)
> > Calling destroy() at exit time feels like dealing with the issue
> > with brute force instead of properly cleaning up when
> > deactivating the widget.
> 
> destroy() itself does not end the application, only the Tk part.
> This simple example may help to illustrate the difference between quit()
> and destroy():
> 
> from Tkinter import *
> 
> def clean_up():
>     print('Cleaning up.')
>     return 0
> root = Tk()
> root.wm_protocol('WM_DELETE_WINDOW', root.quit)
> l = Label(root, text='foo')
> l.pack(padx=100, pady=100)
> root.mainloop()
> print(l['text'])
> root.destroy()
> exitcode = clean_up()
> print(l['text'])
> sys.exit(exitcode)
> 
> 
> As you can see, after quit() is called, the Label widget can still be
> accessed, which fails (and causes the app to crash) after destroy() was
> called. You can also very well perform some clean up routine after
> destroy() has been called, as long as it does not require Tk to still be
> "alive",
> As far as sys.exit() is concerned, I think it should not be necessary to
> use it unless you want to control your app's exit code. Using sys.exit()
> to end the app rather seems to be "brute force" than destroy(). I have no
> idea though why the window won't close without it. Does your app use
> threads? Improper use of threads at least might explain all sorts of odd
> behavior...

No, it is not using threads. The issue seems to be caused by the
presence of another mainloop() (see
edit_pool.py::editPool.activate()). I now noticed that editPool
calls editPool.mainloop() during activation and then
editPool.quit() during deactivation, but the widget itself
remains.

When calling app.quit() the application main loop might be
terminated, but it doesn't get to execute the app.destroy() call,
probably because the editPool widget is still alive and needs to
be destroyed before continuing.

The source of non-zero exit code with the sys.exit() call seems
to be the presence of the app and editPool widgets left after the
app.quit().

It seems that calling app.destroy() in place of app.quit() takes
care of destroying also the editPool widget and the app
terminates cleanly.

I don't want to destroy editPool when deactivated, because I want
the widget to be visible in the UI (instead of blank space). So
the solution of calling app.destroy() in place of app.quit()
seems to be the correct one for this case.

Is such use of nested mainloops considered an error? Is there a
better way of doing this?


Reinis


More information about the Tkinter-discuss mailing list