Ruby/Tk - simple task that I'm srtuck

I have:
1. $lb_1 = TkLabel.new(root){..} - label
2. bt_toss=TkButton.new(root){..} - button

I want when I press the button: 1. label's background is changed
to blue
                                        2. display changed label's
background
                                        3. sleep(0.5)
                                        4. label's background is changed
to green
                                        5. display changed label's
background

but I see only the last colour.

here the code:

require 'tk'

root = TkRoot.new { title "Ruby/Tk Example" }

$lb_1 = TkLabel.new(root){
background "red"
foreground "blue"
text "Your area"
font "system,12"
place('relx'=>0.4, 'rely'=>0.08)
}

bt_toss=TkButton.new(root){
text "Toss"
command proc{change_colour}
place('relx'=>0.2, 'rely'=>0.78)
}

def change_colour
  $lb_1.configure('background'=>'blue')
  sleep(0.5)
  $lb_1.configure('background'=>'green')
  sleep(0.5)
  $lb_1.configure('background'=>'gray')

end

Tk.mainloop

···

--
Posted via http://www.ruby-forum.com/.

I have:
1. $lb_1 = TkLabel.new(root){..} - label
2. bt_toss=TkButton.new(root){..} - button

I want when I press the button: 1. label's background is changed to blue
                                        2. display changed label's background
                                        3. sleep(0.5)
                                        4. label's background is changed to green
                                        5. display changed label's background

but I see only the last colour.

You only see the last color because you don't call update on the label widget after you change the background color.

here the code:

require 'tk'

root = TkRoot.new { title "Ruby/Tk Example" }

$lb_1 = TkLabel.new(root){
background "red"
foreground "blue"
text "Your area"
font "system,12"
place('relx'=>0.4, 'rely'=>0.08)
}

bt_toss=TkButton.new(root){
text "Toss"
command proc{change_colour}
place('relx'=>0.2, 'rely'=>0.78)
}

def change_colour
  $lb_1.configure('background'=>'blue')
  sleep(0.5)
  $lb_1.configure('background'=>'green')
  sleep(0.5)
  $lb_1.configure('background'=>'gray')

end

Tk.mainloop

I strongly urge you to avoid using global variables to solve a scoping problem when there are better ways to solve the problem. I've taken the liberty to show you one way to avoid using a global name for the label widget. And I have Ruby-ized your code in a couple of other small ways.

<code>
require 'tk'

ZZZ = 2.0 # longer delay makes color changes easier to see

root = TkRoot.new { title "Ruby/Tk Example" }

lbl = TkLabel.new(root) {
    background "red"
    foreground "blue"
    text "Your area"
    # bigger font just to make text easier to see
    font "system, 24"
    place('relx' => 0.2, 'rely' => 0.08)
}

def lbl.change_colour
    # this is a singleton method; self is now the TkLabel object
    # also Ruby/Tk will build Tk configure calls for you
    background('blue')
    update # this makes the color change happen on the screen
    sleep(ZZZ)
    background('green')
    update
    sleep(ZZZ)
    background('gray')
end

# The local variable 'lbl' is visible in the black because
# the block is a closure.
callback = lambda { lbl.change_colour }

TkButton.new(root) {
    text "Toss"
    command callback
    place('relx' => 0.35, 'rely' => 0.8)
}

Tk.mainloop
</code>

Regards, Morton

···

On Jun 26, 2007, at 7:44 AM, Valen Onish wrote:

Message-ID: <b60191be5fbf2368e9bc896c10520af4@ruby-forum.com>

but I see only the last colour.

You'll be able to see the changes by 'Tk.update_idletasks'.
For example,

···

From: Valen Onish <valenonish@gmail.com>
Subject: Ruby/Tk - simple task that I'm srtuck
Date: Tue, 26 Jun 2007 20:44:06 +0900
-------------------------------------
def change_colour
  $lb_1.configure('background'=>'blue')
  Tk.update_idletasks
  sleep(0.5)
  $lb_1.configure('background'=>'green')
  Tk.update_idletasks
  sleep(0.5)
  $lb_1.configure('background'=>'gray')
end
-------------------------------------

However, that NEVER be a right solution,
because a 'sleep' method on a callback procedure
blocks Tk's eventloop.
Then, there are no drawing, no update of widgets,
and no response to events.

I recommend you to use 'Tk.after' method or a TkTimer object.
For example,

---< Tk.after >---------------------------------------
require 'tk'

root = TkRoot.new { title "Ruby/Tk Example" }

lb_1 = TkLabel.new(root){
background "red"
foreground "blue"
text "Your area"
font "system,12"
place('relx'=>0.4, 'rely'=>0.08)
}

bt_toss=TkButton.new(root){
text "Toss"
command proc{change_colour(bt_toss, lb_1)}
place('relx'=>0.2, 'rely'=>0.78)
}

def change_colour(btn, lbl)
  btn.state = :disabled
  lbl.configure('background'=>'blue')
  Tk.after(500){lbl.configure('background'=>'green')}
  Tk.after(1000){lbl.configure('background'=>'gray'); btn.state = :normal}
# OR
# Tk.after(500){
# lbl.configure('background'=>'green')
# Tk.after(500){lbl.configure('background'=>'gray'); btn.state = :normal}
# }
end

Tk.mainloop
------------------------------------------------------

In this case, it is better to disable the button while changing the
label's color.
If not disable, multiple clicks may break the changing order of colors.

If you want to allow multiple clicks, you have to stop the Tk.after
callbacks. It may bother you.
In such case, TkTimer#restart is useful.
For example,

---< TkTimer >----------------------------------------
require 'tk'

root = TkRoot.new { title "Ruby/Tk Example" }

lb_1 = TkLabel.new(root){
background "red"
foreground "blue"
text "Your area"
font "system,12"
place('relx'=>0.4, 'rely'=>0.08)
}

timer = TkTimer.new(500, 1, # interval == 500ms repeat == once
                    proc{|tm_obj|
                      tm_obj.return_value.configure(:background => 'green')
                      # tm_obj.return_value == lb_1
                    },
                    proc{|tm_obj|
                      tm_obj.return_value.configure(:background => 'gray')
                    })

timer.set_start_proc(0, # wait before start == 0 ms
                     proc{|tm_obj|
                       tm_obj.current_args[0].configure(:background => 'blue')
                       # tm_obj == TkTimer object
                       # tm_obj.current_args == [lb_1]
                       # return_value is lb_1
                       # ( == tm_obj.return_value on the next callback )
                     }, lb_1)

bt_toss=TkButton.new(root){
text "Toss"
command proc{timer.restart}
place('relx'=>0.2, 'rely'=>0.78)
}

Tk.mainloop
------------------------------------------------------
--
Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Thanks Morton! You really helped me.

···

--
Posted via http://www.ruby-forum.com/.

Thanks Hidetoshi! I appreciate your help.

···

--
Posted via http://www.ruby-forum.com/.