Ruby / TK 按钮事件处理程序代码未按预期触发
以下代码创建 3 个按钮并向每个按钮添加一个处理程序。 “退出”按钮起作用,“放弃”按钮产生错误 NameError 未知选项 settings_change 并表明对象已被删除。与“下一步”按钮相同。当我将事件处理程序放在类之外时,代码可以正常工作。
事实证明,如果通过首先执行类似 next_note_proc = proc {next_note} 的操作来创建回调,那么在按钮创建中执行命令 next_note_proc。为什么这个有效?
为什么回调在类内部和外部的工作方式不同?
require 'tk'
require 'tkextlib/tile'
class App
def next_note
puts "Got next note"
end
def settings_change
puts "Got settings change"
end
def quit
puts "Got exit"
exit(1)
end
def initialize
$number_correct = TkVariable.new;
$mode = TkVariable.new
@root = TkRoot.new {title "Music Training"}
@content = Tk::Tile::Frame.new(@root) {padding "0 0 0 0"}.grid( :sticky => 'nsew')
@a = Tk::Tile::Button.new(@content) {text 'Next'; command {next_note}}.grid( :column => 1, :row => 1, :sticky => 'w')
@b = Tk::Tile::Button.new(@content) {text 'Give up'; command {settings_change}}.grid( :column => 2, :row => 1, :sticky => 'w')
@c = Tk::Tile::Button.new(@content) {text 'Quit'; command {quit}}.grid( :column => 2, :row => 2, :sticky => 'w')
TkWinfo.children(@content).each {|w| TkGrid.configure w, :padx => 0, :pady => 0}
@c.bind("1") {quit}
@a.bind("1") {next_note}
@b.bind("1") {settings_change}
puts "Starting up"
end
def run
Tk.mainloop
end
end
the_app = App.new
the_app.run
The following code creates 3 buttons and adds a handler to each one. The Quit button works, the Give Up button produces an error NameError unknown option settings_change and suggests that an object has been deleted. Same with the Next button. The code works ok when I put the event handlers outside the class.
It turns out that if a callback is created by first doing something like next_note_proc = proc {next_note}, then in the button creation do command next_note_proc. Why does this work??
Why do the callbacks work differently when inside or outside the class?
require 'tk'
require 'tkextlib/tile'
class App
def next_note
puts "Got next note"
end
def settings_change
puts "Got settings change"
end
def quit
puts "Got exit"
exit(1)
end
def initialize
$number_correct = TkVariable.new;
$mode = TkVariable.new
@root = TkRoot.new {title "Music Training"}
@content = Tk::Tile::Frame.new(@root) {padding "0 0 0 0"}.grid( :sticky => 'nsew')
@a = Tk::Tile::Button.new(@content) {text 'Next'; command {next_note}}.grid( :column => 1, :row => 1, :sticky => 'w')
@b = Tk::Tile::Button.new(@content) {text 'Give up'; command {settings_change}}.grid( :column => 2, :row => 1, :sticky => 'w')
@c = Tk::Tile::Button.new(@content) {text 'Quit'; command {quit}}.grid( :column => 2, :row => 2, :sticky => 'w')
TkWinfo.children(@content).each {|w| TkGrid.configure w, :padx => 0, :pady => 0}
@c.bind("1") {quit}
@a.bind("1") {next_note}
@b.bind("1") {settings_change}
puts "Starting up"
end
def run
Tk.mainloop
end
end
the_app = App.new
the_app.run
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从按钮执行的命令在全局上下文中运行,但
settings_change
、quit
和next_note
位于类的上下文中。当您使用 proc 命令时,它会创建一个新的 Proc 对象,该对象调用该方法,并且可以从其他上下文调用该对象。quit
命令似乎起作用的原因可能是因为在全局范围内有另一个quit
命令被调用——它几乎是当然不会调用App
对象的quit
方法。您可以通过在quit
方法中添加打印语句来验证这一点。Commands executed from buttons run in the global context, but
settings_change
,quit
andnext_note
are in the context of the class. When you use theproc
command it creates a newProc
object which calls the method, and which can be called from other contexts.The reason the
quit
command seems to work is probably because there is anotherquit
command at the global scope that is getting called -- it is almost certainly not calling thequit
method of theApp
object. You can verify that by adding a print statement in thequit
method.