How to terminate a TkinterApp correctly?

Discussion in 'Python' started by Gregor Lingl, Aug 16, 2003.

  1. Gregor Lingl

    Gregor Lingl Guest

    I'm working on a windows machine

    I've written a Tkinter-app (sort of game) which
    consists mainly of an animation which is driven
    by a while True: ... loop.

    If I close the App's window by clicking the
    right upper standard-X-Button, the program
    doesn't terminate cleanly. Instead a somewhat
    cryptic error message is displayed, e.g.:

    .....
    TclError: invalid command name ".12880040.12880944"

    which - I suppose - stems from the interpreter trying
    to execute some statement in the infinite loop.

    Only if this loop is terminated by some other means
    - e.g. game over - before closing the window no
    error message is displayed.

    How, i.e. by what sort of event handler or error handler
    can I avoid this annoying behaviour of my program?

    Regards, Gregor
    Gregor Lingl, Aug 16, 2003
    #1
    1. Advertising

  2. "Gregor Lingl" <> schrieb im Newsbeitrag
    news:...
    > I'm working on a windows machine
    >
    > I've written a Tkinter-app (sort of game) which
    > consists mainly of an animation which is driven
    > by a while True: ... loop.
    >

    [....]
    > Only if this loop is terminated by some other means
    > - e.g. game over - before closing the window no
    > error message is displayed.
    >


    Correct

    > How, i.e. by what sort of event handler or error handler
    > can I avoid this annoying behaviour of my program?
    >


    You can bind <Destroy> and act accordimngly, or intercept the action
    altogether.

    Example:
    -----------------------------
    from Tkinter import *

    def killingAction(ev):
    print "Destroyed"

    def kidding():
    print "not killing"
    l.config(text="just kidding")
    l.master.protocol("WM_DELETE_WINDOW",original)

    l=Label(text="Kill me!")
    l.pack()
    l.bind("<Destroy>",killingAction)

    original= l.master.protocol("WM_DELETE_WINDOW",None)
    l.master.protocol("WM_DELETE_WINDOW",kidding)
    l.master.destroy=lambda: 0

    mainloop()
    --------------------------------------------

    Kindly
    Michael P


    > Regards, Gregor
    >
    Michael Peuser, Aug 16, 2003
    #2
    1. Advertising

  3. I just notice a left over line from a test, that lambda is of no use at all!
    May be you will have to use WM_SAVE_YOURSELF instead of WM_DELETE_WINDOWS if
    you want to be sure to keep the widget absolutly intact. Between these two
    messages some tidying-up could aleady have happened behind the scene....So
    this is my fine example:

    -----------------------------
    from Tkinter import *

    def killingAction(ev):
    print "Destroyed"

    def kidding():
    print "not killing"
    l.config(text="just kidding")
    l.master.protocol("WM_DELETE_WINDOW",original)

    l=Label(text="Kill me!")
    l.pack()
    l.bind("<Destroy>",killingAction)

    original= l.master.protocol("WM_DELETE_WINDOW",None)
    l.master.protocol("WM_DELETE_WINDOW",kidding)


    mainloop()
    -------------------------------------------

    Kindly
    Michael P
    Michael Peuser, Aug 16, 2003
    #3
  4. ----- Original Message -----
    From: "Gregor Lingl" <>
    Newsgroups: comp.lang.python
    Sent: Saturday, August 16, 2003 3:53 PM
    Subject: Re: How to terminate a TkinterApp correctly?

    .....

    > Thanks for your remarks and your example. The
    > following solution finally did it:
    >
    > def exit():
    > global done
    > done = True # so the animation will terminate, but
    > # not immediately! The actual pass through
    > # the loop has to be finished.
    > print "done!"
    > import sys
    > # after_idle seems to be crucial! Waits for terminating
    > # the loop (which is in a callback function)
    > cv.after_idle(sys.exit, (0,))



    Why don't you just return? The mainloop can handle everything!?
    Example:
    def exit(self):
    self.done=1
    return

    (If you can put it into an appropriate class ....)

    >
    > cv.master.protocol("WM_DELETE_WINDOW", exit)
    >
    > if not usingIDLE:
    > root.mainloop()
    >
    > Regards, Gregor
    >
    Michael Peuser, Aug 16, 2003
    #4
  5. Gregor Lingl

    John Roth Guest

    "Michael Peuser" <> wrote in message
    news:bhlmgq$dqk$02$-online.com...
    >
    > ----- Original Message -----
    > From: "Gregor Lingl" <>
    > Newsgroups: comp.lang.python
    > Sent: Saturday, August 16, 2003 3:53 PM
    > Subject: Re: How to terminate a TkinterApp correctly?
    >
    > ....
    >
    > > Thanks for your remarks and your example. The
    > > following solution finally did it:
    > >
    > > def exit():
    > > global done
    > > done = True # so the animation will terminate, but
    > > # not immediately! The actual pass through
    > > # the loop has to be finished.
    > > print "done!"
    > > import sys
    > > # after_idle seems to be crucial! Waits for terminating
    > > # the loop (which is in a callback function)
    > > cv.after_idle(sys.exit, (0,))

    >
    >
    > Why don't you just return? The mainloop can handle everything!?


    Unfortunately, the combination of Windows 9x (including Me)
    and Python 2.1 can't handle everything. It may also be broken
    in 2.2 and later, but I quit trying after reaching my frustration
    limit. If you exit with an exception, something doesn't clean up
    properly, and you break the DOS box and eventually Windows
    itself when you try to shut down.

    This problem doesn't exist in the Windows 2K (including XP)
    code base, or other variants.

    I don't know that it's ever been solved, but considering that
    Windows 9x is gradually going away, it's also not a real hot
    priority.

    John Roth
    John Roth, Aug 16, 2003
    #5
  6. "John Roth" <> schrieb im Newsbeitrag
    news:...
    >
    > "Michael Peuser" <> wrote in message
    > news:bhlmgq$dqk$02$-online.com...
    > >
    > > ----- Original Message -----
    > > From: "Gregor Lingl" <>
    > > Newsgroups: comp.lang.python
    > > Sent: Saturday, August 16, 2003 3:53 PM
    > > Subject: Re: How to terminate a TkinterApp correctly?
    > >
    > > ....
    > >
    > > > Thanks for your remarks and your example. The
    > > > following solution finally did it:
    > > >
    > > > def exit():
    > > > global done
    > > > done = True # so the animation will terminate, but
    > > > # not immediately! The actual pass through
    > > > # the loop has to be finished.
    > > > print "done!"
    > > > import sys
    > > > # after_idle seems to be crucial! Waits for terminating
    > > > # the loop (which is in a callback function)
    > > > cv.after_idle(sys.exit, (0,))

    > >
    > >
    > > Why don't you just return? The mainloop can handle everything!?

    >
    > Unfortunately, the combination of Windows 9x (including Me)
    > and Python 2.1 can't handle everything. It may also be broken
    > in 2.2 and later, but I quit trying after reaching my frustration
    > limit. If you exit with an exception, something doesn't clean up
    > properly, and you break the DOS box and eventually Windows
    > itself when you try to shut down.
    >
    > This problem doesn't exist in the Windows 2K (including XP)
    > code base, or other variants.
    >
    > I don't know that it's ever been solved, but considering that
    > Windows 9x is gradually going away, it's also not a real hot
    > priority.



    This was not my point I think.... I was not referring to tk/system mainloop
    but to your own loop you mentioned. This is where you set "done=1" for...
    The after_idle is confusing and probably not what you want. I have the
    impression that there is still some misunderstanding.

    It is absolutly fine to intercept the user click to the close box - there is
    no magic it and - as to my example - you can do what you want for hours
    after. Note: the "closing" process is stopped, when you use this WM-....
    trick. (Because I was not *quite* sure about the internal states, I also
    recommende to use WM_SAVE_YOURSELF instead).

    But I think it is not worth all the work - and still unsafe! - to just call
    sys.exit() !!!

    Kindly Michasel P


    > John Roth
    >
    >
    >
    Michael Peuser, Aug 16, 2003
    #6
  7. Gregor Lingl

    Gregor Lingl Guest

    Michael Peuser schrieb:

    > ----- Original Message -----
    > From: "Gregor Lingl" <>
    > Newsgroups: comp.lang.python
    > Sent: Saturday, August 16, 2003 3:53 PM
    > Subject: Re: How to terminate a TkinterApp correctly?
    >
    > ....
    >
    >
    >>Thanks for your remarks and your example. The
    >>following solution finally did it:
    >>
    >>def exit():
    >> global done
    >> done = True # so the animation will terminate, but
    >> # not immediately! The actual pass through
    >> # the loop has to be finished.
    >> print "done!"
    >> import sys
    >> # after_idle seems to be crucial! Waits for terminating
    >> # the loop (which is in a callback function)
    >> cv.after_idle(sys.exit, (0,))

    >
    >
    >
    > Why don't you just return? The mainloop can handle everything!?
    > Example:
    > def exit(self):
    > self.done=1
    > return
    >

    Here I apparently don't understand something fundamental:
    what is the effect of a return statement as the last statement
    of a function?
    Moreover: If I put this into the cv.master.protocol ... I cannot
    close the application at all. (Because the original is not restored.
    And I don't want to need a second mouseclick as in your first example.)
    Gregor
    > (If you can put it into an appropriate class ....)
    >
    >
    >>cv.master.protocol("WM_DELETE_WINDOW", exit)
    >>
    >>if not usingIDLE:
    >> root.mainloop()
    >>
    >>Regards, Gregor
    >>

    >
    >
    >
    Gregor Lingl, Aug 16, 2003
    #7
  8. Gregor Lingl

    Gregor Lingl Guest

    Michael Peuser schrieb:

    > "John Roth" <> schrieb im Newsbeitrag

    ....

    >>>Why don't you just return? The mainloop can handle everything!?

    >>
    >>Unfortunately,


    ....
    >>I don't know that it's ever been solved, but considering that
    >>Windows 9x is gradually going away, it's also not a real hot
    >>priority.

    >
    >
    >
    > This was not my point I think.... I was not referring to tk/system mainloop
    > but to your own loop you mentioned.


    The above answer was not mine, so there is samething a bit mangled ...

    This is where you set "done=1" for...
    > The after_idle is confusing and probably not what you want.


    But it worked!

    I have the
    > impression that there is still some misunderstanding.


    Maybe!

    > It is absolutly fine to intercept the user click to the close box - there is
    > no magic it and - as to my example - you can do what you want for hours
    > after. Note: the "closing" process is stopped, when you use this WM-....
    > trick. (Because I was not *quite* sure about the internal states, I also
    > recommende to use WM_SAVE_YOURSELF instead).
    >
    > But I think it is not worth all the work - and still unsafe! -


    WHY?

    to just call
    > sys.exit() !!!


    So I found another working solution to my problem:
    I put the code for the go-function, which is the command of a goButton
    in a try:- except: clause.

    def go():
    global done
    try:
    resetGame()
    goButton["state"] = Tk.DISABLED
    while fehler < MAXFEHLER and not done:
    for huhn in huehner:
    huhn.move()
    cv.update()
    done = True
    goButton["state"] = Tk.NORMAL
    except:
    pass

    This catches the TclError and everything terminates regularly
    Regards, Gregor

    > Kindly Michasel P
    >
    >
    >
    >>John Roth
    >>
    >>
    >>

    >
    >
    >
    Gregor Lingl, Aug 16, 2003
    #8
  9. "Gregor Lingl" <> schrieb im Newsbeitrag
    news:...
    > Michael Peuser schrieb:


    .....

    > > Why don't you just return? The mainloop can handle everything!?
    > > Example:
    > > def exit(self):
    > > self.done=1
    > > return
    > >

    > Here I apparently don't understand something fundamental:
    > what is the effect of a return statement as the last statement
    > of a function?


    Nothing, just an indicator to make clear that this is the end of the
    procedure...

    > Moreover: If I put this into the cv.master.protocol ... I cannot
    > close the application at all. (Because the original is not restored.
    > And I don't want to need a second mouseclick as in your first example.)



    This is a misunderstanding. Closing your application has nothing to do with
    closing some window and even less with where a stupid user clicks on ;-)

    You can destroy a widget with "destroy"; when the root widget is destroyed
    then the Tkinter mainloop terminats by convention. Nothing to do with your
    program!!


    See this example:
    ---------------------------
    from Tkinter import *

    def killingAction():
    l.master.destroy()

    def kidding():
    l.config(text="just kidding")


    l=Button(text="Kill me!",command=killingAction)
    l.pack()

    l.master.protocol("WM_DELETE_WINDOW",kidding)


    mainloop()
    print "here we are- ready for whatever we want"
    -----------------------
    Michael Peuser, Aug 16, 2003
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter
    Replies:
    0
    Views:
    499
    Peter
    Aug 28, 2004
  2. Denon
    Replies:
    1
    Views:
    2,034
  3. Denon
    Replies:
    0
    Views:
    372
    Denon
    Nov 14, 2003
  4. Denon
    Replies:
    0
    Views:
    392
    Denon
    Nov 14, 2003
  5. tom
    Replies:
    0
    Views:
    1,467
Loading...

Share This Page