如何解决Ruby Proc 为 Ruby Tkinter 中的所有按钮点击返回相同的值
我正在使用 Ruby Tkinter 开发一个应用程序,但在为循环中的按钮定义事件时遇到了问题。
以下面的代码为例:
array = ["one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"]
new_array = []
for i in 0..(array.length - 1)
new_array.append [i,Proc.new {puts array[i]}]
end
for i in 0..(new_array.length - 1)
new_array[i][1].call
end
当上面的代码运行时,我得到了预期的输出:
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
但是如果我想应用相同的概念为我的 Tkinter 应用程序在循环中创建一组按钮:
require 'tk'
root = TkRoot.new()
root.title("Test")
list = ["one","twelve"]
for i in (0..list.length - 1)
button = Tk::Tile::Button.new(root).pack :side => "top",:expand => false,:fill => "x"
button.text = (i + 1).to_s
button.command = Proc.new {puts list[i]}
end
Tk.mainloop
如果我按下上面代码中窗口中的所有按钮,我会得到这个输出:
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
这是怎么回事?为什么我的按钮事件都一样? 我在 Python 中看到了一些关于 Tk 的“后期事件绑定”问题,但我找不到很多解决方案。尤其不适用于 Ruby。
解决方法
这是一个常见的闭包问题:当调用 i
时,procs 最终会引用 Proc.new
本身而不是它的值。这在 JavaScript 中比在 Ruby 中更常见,因为循环在 Ruby 中很少使用。
最简单的 Ruby 解决方案是根本不使用循环:
list.each_with_index do |item,i|
button = Tk::Tile::Button.new(root).pack side: 'top',expand: false,fill: 'x'
button.text = (i + 1).to_s
button.command = Proc.new { puts item }
end
你也可以说:
list.length.times do |i|
button = Tk::Tile::Button.new(root).pack side: 'top',fill: 'x'
button.text = (i + 1).to_s
button.command = Proc.new { puts list[i] }
end
但 each_with_index
更惯用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。