MC logo

Binding and Actions

^  Ruby Example Code

<<Bouncing Balls varaction.rb FTP Download Tool>>
#
# This shows a potential problem in providing button actions.  The code blocks
# are run in the context of the caller, but not until the button is pressed.  
# Therefore variable values are current as of the button press.  This is not
# always what you want.
#
require 'tk'

# Root window
root = TkRoot.new

# Three buttons created in a loop, numbering from 1 to 3.
bnum = 1
for fred in [ 17, 348, -48 ]
  TkButton.new(root) {
    text "Button " + bnum.to_s
    command proc { print "Button ", bnum, ", fred = ", fred, "\n" }
    grid('column' => 0, 'row' => bnum-1, 'sticky' => 'news')
  }

  bnum += 1
end

# This holds and prints two values.  The parms are evaluated when the
# object is created, so we get the right values.  The button command
# will use any object which understands the call method.
class Printer
  def initialize(num, fred)
    @num = num
    @fred = fred
  end
  def call
    print "Button ", @num, ", fred = ", @fred, "\n"
  end
end

# Three more buttons, but this time they use the Printer class and work
# correctly.
for fred in [ 'Dogbert', 97, 111 ]
  TkButton.new(root) {
    text "Button " + bnum.to_s
    command Printer.new(bnum, fred)
    grid('column' => 1, 'row' => bnum-4, 'sticky' => 'news')
  }

  bnum += 1
end

# This is a more generic solution
class Runner
  # Set a proc and some args.
  def initialize(method, *args)
    @method = method
    @args = args
  end

  # Run it with the args.
  def call
    @method.call(*@args)
  end
end

# Three more, but this time they work correctly.
for fred in [ 86, 12, 123 ]
  TkButton.new(root) {
    text "Button " + bnum.to_s
    command Runner.new(proc { |n, f| 
                         print "Button ", n, ", fred = ", f, "\n" }, 
                       bnum, fred)
    grid('column' => 2, 'row' => bnum-7, 'sticky' => 'news')
  }

  bnum += 1
end

# These are sort of button-like, but use binding.
lnum = 1
for fred in [ 2973, 'Nosebleed', 349 ]
  b = TkLabel.new(root) {
    text "Label " + lnum.to_s
    grid('column' => 3, 'row' => lnum-1, 'sticky' => 'news')
    relief 'raised'
    background '#999999'
    padx 10
  }
  b.bind('Button-1', 
         proc { print "Label ", lnum, ", fred = ", fred, "\n" })

  lnum += 1
end

# This shows a nice feature of bind which allows extra parameters to be
# sent in.
for fred in [ 98733, 128, 'Norbert' ]
  b = TkLabel.new(root) {
    text "Label " + lnum.to_s
    grid('column' => 4, 'row' => lnum-4, 'sticky' => 'news')
    relief 'raised'
    background '#999999'
    padx 10
  }
  b.bind('Button-1', 
         proc { | n, f | print "Label ", n, ", fred = ", f, "\n" }, lnum, fred)

  lnum += 1
end

Tk.mainloop

<<Bouncing Balls FTP Download Tool>>