Hidetoshi NAGAI
4/6/2009 9:51:00 PM
From: Diego Virasoro <Diego.Virasoro@gmail.com>
Subject: Ruby/Tk refresh problem
Date: Mon, 6 Apr 2009 19:39:15 +0900
Message-ID: <14fd4ffc-9fc4-4a36-bf2e-a0bb7b278d5f@f19g2000yqo.googlegroups.com>
> I am using Ruby 1.8.7 with Tk. The code runs fine. However, a few
> instructions that I set while the program is busy (basically before
> starting heavy computation it sets a TkLabel to display "Busy"... and
> once it's done it sets it back to "") do not seem to have much of an
> effect.
Maybe, you call the heavy computation *IN* a callback.
If so, that is a very bad way on event-driven programing.
The heavy part blocks the eventloop.
And then, the GUI cannot receive any events.
That is, the GUI seems to freeze.
A callback procedure should return as soon as possible.
One of the simple way to do that is to make a thread executing the
heavy computation.
Of course, you never join the thread in a callback.
Instead of joining, you should generate an event (TkVariable#wait may
be useful) to tell the finishing of the thread.
For example, the following is a bad sample.
------------------------------------------------------------------
require 'tk'
l = TkLabel.new(:text=>'MESSAGE').pack
TkTimer.new(500, -1,
proc{l.foreground 'black'},
proc{l.foreground 'red'}).start
TkButton.new(:text=>'start heavy work',
:command=>proc{10.times{|n| sleep 1; p n}}).pack
Tk.mainloop
------------------------------------------------------------------
When clicking the button, this GUI seems to freeze.
Please compare with the following.
------------------------------------------------------------------
require 'tk'
l = TkLabel.new(:text=>'MESSAGE').pack
TkTimer.new(500, -1,
proc{l.foreground 'black'},
proc{l.foreground 'red'}).start
TkButton.new(:text=>'start heavy work',
:command=>proc{Thread.new{10.times{|n| sleep 1; p n}}}).pack
Tk.mainloop
------------------------------------------------------------------
The following is another sample.
------------------------------------------------------------------
require 'tk'
l = TkLabel.new(:text=>'MESSAGE').pack
TkTimer.new(500, -1,
proc{l.foreground 'black'},
proc{l.foreground 'red'}).start
b = TkButton.new(:text=>'start heavy work',
:command=>proc{
b.state :disable
Thread.new{
10.times{|n| sleep 1; p n}
b.state :normal
}
}).pack
Tk.mainloop
------------------------------------------------------------------
This example shows one of the way to catch the finishing of a heavy
operation.
--
Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)