Mailing List Archive

Tkinter - the app that wouldn't quit
--tThc/1wpZn/ma/RB
Content-Type: text/plain; charset=us-ascii

I'm writing a test wrapper for a dialog module that doesn't terminate
the application. How can I exit the test program when the dialog is
dismissed?

Attached is a minimal version that illustrates the problem. When it
self.destroy()'s itself, we're hung. mainloop() is still spinning.
As you can see, I did try WM_DELETE_WINDOW.

Thanks for any tips,

Randall


--tThc/1wpZn/ma/RB
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="dialog.py"

#!/usr/bin/env python

import sys
from Tkinter import *
from ScrolledText import ScrolledText

class CommandWindow(ScrolledText):

def __init__(self, master=None, **cnf):
apply(ScrolledText.__init__, (self, master), cnf)

class CommandWindowDialog(Toplevel):

def __init__(self, master=None, **cnf):
apply(Toplevel.__init__, (self, master), cnf )
self.title( 'COMMAND OUTPUT' )
win = CommandWindow( self )
win.pack(expand=1, fill=X)
btn = Button( self, text="Quit", command=self.destroy )
btn.pack()

root = Tk()
w = CommandWindowDialog( root )
w.protocol( 'WM_DELETE_WINDOW', sys.exit )
root.wm_withdraw()
w.mainloop()

--tThc/1wpZn/ma/RB--
Tkinter - the app that wouldn't quit [ In reply to ]
I would suggest to use Pmw (http://www.dscpl.com.au/pmw/) which
contains ready-to-use dialog windows.

The problem in your current program appears to be that when your
application window is destroyed, "root" is still an active window,
although it is invisible.

The WM_DELETE protocol is never called, because you're not
"destroying" the window using the window manager.

The smallest change would be to make the "Quit" button run "sys.exit"
immediately instead of "self.destroy".

Regards,

--
===== R.Hooft@EuroMail.net http://www.xs4all.nl/~hooft/rob/ =====
===== R&D, Nonius BV, Delft http://www.nonius.nl/ =====
===== PGPid 0xFA19277D ========================== Use Linux! =========
Tkinter - the app that wouldn't quit [ In reply to ]
--C7zPtVaVf+AK4Oqc
Content-Type: text/plain; charset=us-ascii

Rob Hooft:
|The problem in your current program appears to be that when your
|application window is destroyed, "root" is still an active window,
|although it is invisible.
|
|The WM_DELETE protocol is never called, because you're not
|"destroying" the window using the window manager.

Ok. That makes sense.

|The smallest change would be to make the "Quit" button run "sys.exit"
|immediately instead of "self.destroy".

The problem here is that this is supposed to be a reusable dialog which
doesn't exit the app. In reality, the button says "Dismiss" not "Quit".
Hitting it just destroys the dialog (and all the processing guts inside,
which I've deleted) and the app continues.

Only for the test wrapper do I want to exit the app -- since it's the only
window displayed.

Do I need to add special testing-harness hooks into the dialog class, or is
there a general way to determine when a dialog destroys/unmaps itself from
outside of the dialog code?

Randall

--C7zPtVaVf+AK4Oqc
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="dialog.py"

#!/usr/bin/env python

import sys
from Tkinter import *
from ScrolledText import ScrolledText

class CommandWindow(ScrolledText):

def __init__(self, master=None, **cnf):
apply(ScrolledText.__init__, (self, master), cnf)

class CommandWindowDialog(Toplevel):

def __init__(self, master=None, **cnf):
apply(Toplevel.__init__, (self, master), cnf )
self.title( 'COMMAND OUTPUT' )
win = CommandWindow( self )
win.pack(expand=1, fill=X)
btn = Button( self, text="Quit", command=self.destroy )
btn.pack()

root = Tk()
w = CommandWindowDialog( root )
w.protocol( 'WM_DELETE_WINDOW', sys.exit )
root.wm_withdraw()
w.mainloop()

--C7zPtVaVf+AK4Oqc--
Tkinter - the app that wouldn't quit [ In reply to ]
>>>>> "RH" == Randall Hopper <aa8vb@vislab.epa.gov> writes:

RH> Do I need to add special testing-harness hooks into the dialog
RH> class, or is there a general way to determine when a dialog
RH> destroys/unmaps itself from outside of the dialog code?

Using Tkinter, you can "wait" for a few specific events.

"w.wait_window()" will wait for w to be destroyed. But even then, a
destroyed window can not be reused!

Alternatively wait_visibility() and wait_variable() methods can be used.

I come back to my advertisement: in the *Dialog() classes in the Pmw
framework this has all been programmed (using a wait_variable in that
case); there is no real reason except "the fun of it" to reinvent this
wheel...

Regards,

Rob Hooft.

--
===== R.Hooft@EuroMail.net http://www.xs4all.nl/~hooft/rob/ =====
===== R&D, Nonius BV, Delft http://www.nonius.nl/ =====
===== PGPid 0xFA19277D ========================== Use Linux! =========
Tkinter - the app that wouldn't quit [ In reply to ]
Rob Hooft:
|>>>>> "RH" == Randall Hopper <aa8vb@vislab.epa.gov> writes:
|
| RH> Do I need to add special testing-harness hooks into the dialog
| RH> class, or is there a general way to determine when a dialog
| RH> destroys/unmaps itself from outside of the dialog code?
|
|Using Tkinter, you can "wait" for a few specific events.
|
|"w.wait_window()" will wait for w to be destroyed. But even then, a
|destroyed window can not be reused!

Ahh, perfect. Just what I was looking for.

|I come back to my advertisement: in the *Dialog() classes in the Pmw
|framework this has all been programmed (using a wait_variable in that
|case); there is no real reason except "the fun of it" to reinvent this
|wheel...

Well, there's another reason. I'm at the getting-up-to-speed stage with
Python and Tkinter, and I want to understand the fundamentals before I go
layering other libraries on top.

But thanks for the pointer. I'd found Pmw before and do plan to use it in
my next project. It looks like it can save me a good bit of time for the
off-canvas portions.

Randall