Ruby Proc returns 在 Ruby Tkinter 中所有按钮点击的相同值
Ruby Proc returns the same value for all button clicks in 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","two","three","four","five","six","seven","eight","nine","ten","eleven","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
如果我按下上面代码中 window 中的所有按钮,我会得到这个输出:
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
这是怎么回事?为什么我的按钮事件都是一样的? 我在 Python 中看到过关于 Tk 的“后期事件绑定”问题,但我没能找到很多解决方案。特别是 Ruby.
这是一个常见的闭包问题:当 Proc.new
被调用时,过程最终引用 i
本身而不是它的值。这在 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', expand: false, fill: 'x'
button.text = (i + 1).to_s
button.command = Proc.new { puts list[i] }
end
但是 each_with_index
更加地道。
我正在使用 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","two","three","four","five","six","seven","eight","nine","ten","eleven","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
如果我按下上面代码中 window 中的所有按钮,我会得到这个输出:
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
twelve
这是怎么回事?为什么我的按钮事件都是一样的? 我在 Python 中看到过关于 Tk 的“后期事件绑定”问题,但我没能找到很多解决方案。特别是 Ruby.
这是一个常见的闭包问题:当 Proc.new
被调用时,过程最终引用 i
本身而不是它的值。这在 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', expand: false, fill: 'x'
button.text = (i + 1).to_s
button.command = Proc.new { puts list[i] }
end
但是 each_with_index
更加地道。