# # 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