Ruby / TK 按钮事件处理程序代码未按预期触发

发布于 2025-01-02 12:54:47 字数 1402 浏览 1 评论 0原文

以下代码创建 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

命硬 2025-01-09 12:54:47

从按钮执行的命令在全局上下文中运行,但 settings_changequitnext_note 位于类的上下文中。当您使用 proc 命令时,它会创建一个新的 Proc 对象,该对象调用该方法,并且可以从其他上下文调用该对象。

quit 命令似乎起作用的原因可能是因为在全局范围内有另一个 quit 命令被调用——它几乎是当然不会调用 App 对象的 quit 方法。您可以通过在 quit 方法中添加打印语句来验证这一点。

Commands executed from buttons run in the global context, but settings_change, quit and next_note are in the context of the class. When you use the proc command it creates a new Proc 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 another quit command at the global scope that is getting called -- it is almost certainly not calling the quit method of the App object. You can verify that by adding a print statement in the quit method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文