Search code examples
scoperubymotionmousedown

Rubymotion: how can I access instance variable from inside a mouseDown(event) block?


How should I access instance variable inside the mouse event block?
It does not work even if I call other method from the mouse event definition.

The only way I've found for now is to declare the variable as a class variable, but I don't think this is the right way to follow.

updated with new code

app_delegate.rb

class AppDelegate
  def applicationDidFinishLaunching(notification)

    @view = ViewController.new

  end
end

view_controller.rb

class ViewController < NSView

  def init
    @var = "method called from event"
    loadWindow
  end

  def loadWindow
    @window = NSWindow.alloc.initWithContentRect([[400, 500], [480, 200]],
      styleMask: NSTitledWindowMask|NSClosableWindowMask,
      backing: NSBackingStoreBuffered,
      defer: false)
    @window.setTitle("Test")

    @cView = ViewController.alloc.initWithFrame([[400,500], [480, 200]])
    @window.setContentView(@cView)
    @window.orderFrontRegardless
    @window.makeKeyWindow
    runEvent                      # <- This puts "method called from event"
  end

  def runEvent
    puts @var
  end


  def mouseDown event
    runEvent                      # <- This puts a blank line
    puts "mouse click"
  end
end

Solution

  • You're creating two ViewController instances, one with new and one with alloc.initWithFrame().

    new is a class method that directly maps to alloc.init, thus the @view instance is calling .init but the .alloc.initWithFrame() is not.

    The one that is outputting runEvent's contents is the @view instance (when it's created) and the one that's outputting the blank line is @cView's instance (mouseDown).

    You need to set the variable in a common method and then provide an initWithFrame method:

    def initWithFrame(frame)
      super
      setVar
      self
    end
    
    def init
      super
      setVar
      loadWindow
      self
    end
    
    def setVar
      @var = "method called from event"
    end
    

    Works:

    method called from event
    (main)> method called from event
    mouse click
    (main)> method called from event
    mouse click
    

    Two asides: Always call super in an init method you're overriding, and always return self. Also, the way you're loading these ViewController classes is kind of weird; it seems like you could move half the code into the AppDelegate and avoid this ambiguity altogether.