From: Hidetoshi NAGAI Date: 2009-04-07T06:50:57+09:00 Subject: Re: Ruby/Tk refresh problem From: Diego Virasoro 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)