So I have this app
require 'tk'
class Foo
def my_fancy_function
puts "hello, world!"
end
def initialize
@root = TkRoot.new{title "Hello, world!"}
frame = TkFrame.new
my_fancy_button = TkButton.new(frame) do
text "Press meee"
command {my_fancy_function}
pack
end
frame.pack
Tk.mainloop
end
end
bar = Foo.new
But if I press the button, I get "NameError: undefined local variable or method `my_fancy_function' for #<TkBut开发者_StackOverflow社区ton:..."
I'm pretty sure I'm missing something trivial related to scope... how do I bind that command to the button correctly?
Edit: Okay, if I change my my_fancy_button
block to parameters, i.e.
my_fancy_button = TkButton.new(frame, :text => "Press meee", :command => proc{my_fancy_function}).pack
Then it works. But why?
If you put a
p self
into the do ... end
block of your code, then you'll probably find out that the current scope is different than your Foo
object.
Usually, passing blocks to Tk
constructors is unnecessary. The resulting scope is confusing, so I think it should be discouraged.
Examples of same which contain only literal values are inflexible, and teach a bad habit.
Here, a minimal change to your program makes it work, while maintaining readability:
require 'tk'
class Foo
def my_fancy_function
puts "hello, world!"
end
def initialize
@root = TkRoot.new{title "Hello, world!"}
frame = TkFrame.new
my_fancy_button = begin
b = TkButton.new frame
b.text "Press meee"
b.command {my_fancy_function}
b.pack
end
frame.pack
Tk.mainloop
end
end
bar = Foo.new
It works for me using Ruby 2.2.5 (with Tk 8.5.12) on Windows 7.
精彩评论