Tkinter wait_variable hang on exit SOLVED

Russell E. Owen rowen at cesmail.net
Wed Jun 23 23:56:42 CEST 2004


In article <ca550b$9n7$07$1 at news.t-online.com>,
 Peter Otten <__peter__ at web.de> wrote:

><veröffentlicht & per Mail versendet>
>
>Russell E. Owen wrote:
>
>> I want to support execution of simple user-written scripts in a Tkinter
>> application. The scripts should be able to wait for data and such
>> without hanging the GUI (and without having to write the script as a
>> bunch of asynchronously called subroutines).
>> 
>> I decided to use Tkinter's wait_variable. I built a "script runner"
>> object that has suitable wait methods...
>>...
>> Unfortunately, if a user closes the root window while wait_variable is
>> waiting, the application never fully quits. On my unix box the root
>> window closes but the command-line prompt never returns and ^C is
>> ignored. The process isn't using excess cpu cycles; it's just not
>> listening.

>Without any deeper insight in your script - could the following meet your
>needs?
>
>        # instead of atexit.register():
>        def dw():
>            self.cancel()
>            self._tk.destroy()
>        self._tk.protocol("WM_DELETE_WINDOW", dw)
>
>and further down:
>    
>    root = Tkinter.Tk()
>    ScriptRunner._tk = root
>
>That way your runner would get notified if the window shall be closed.

This fix does, indeed work! Also, there is an even easier solution: it 
turns out to be sufficient to bind to <Destroy>. The callback sets the 
variable being waited on and the application no longer hangs.

However, wait_variable proved to unsuitable because if multiple users 
use wait_variable, they stack up. If a new routine executes 
wait_variable while an existing one is waiting, the new routine has to 
fully finish executing before the first one resumes. This is 
understandable in hindsight, but disappointing. As a result:
- only one script could be run at a time
- if wait_variable is used elsewhere (and some dialog boxes are reported 
to do so) then that would also pause an executing script

I ended up implementing user-written scripts as generators, instead. The 
user's script ends up looking like this:
def myscript(sr):
  yield sr.doCmd(...)
  ...
  yield sr.waitMS(...)

where sr is a ScriptRunner object. sr's doCmd, waitMS etc. set up a 
termination condition that causes the script generator's next() method 
to be executed, until the script is finished.

This works fully normally with Tk's event loop. No wait_variable magic 
is involved and multiple scripts can peacefully run at the same time.

The big problem is that users are likely to forget the "yield" 
statement. To help with this I increment one counter each time a wait 
subroutine begins and another counter each time the script generator is 
executed. Any discrepancy indicates a missing yield.

-- Russell



More information about the Python-list mailing list