[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]

Philippe Lang philippe.lang at attiksystem.ch
Sat Oct 7 11:26:03 EDT 2006


I wrote:

> Hi,
> 
> I have read that message handlers can return a value, either
> true or false, depending on if the handler actually did
> something, or not. In the latter case, the message is
> forwarded to the default message handler.
> 
> I have tried this, and found something strange: in this code,
> decommenting: 
> 
>     @data_widget.connect(SEL_KEYPRESS) do |sender, selector, data|   
>         puts d.code false
>     end
> 
> ... breaks the update of the textfield. The handler returns
> false in every case, it should have no effect at all, no?
> 
> I'm I missing something maybe?
> 
> Philippe
> 
> 
> ----------------------------
> #!/usr/bin/ruby
> 
> require 'fox16'
> 
> include Fox
> 
> class MyWindow < FXMainWindow
> 
>   def initialize(app)
> 
>     super(app, "Window", nil, nil, DECOR_ALL, 0, 0, 200, 100)
> 
>     # Menu bar stretched along the top of the main window
>     menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
> 
>     # File menu
>     filemenu = FXMenuPane.new(self)
>     FXMenuTitle.new(menubar, "&File", nil, filemenu)
>     FXMenuCommand.new(filemenu, "&Quit\tCtl-Q\tQuit the application",
>         nil, app, FXApp::ID_QUIT)
> 
>     # Frames
>     frame = FXMatrix.new(self, 4,
>         LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_THICK|FRAME_RAISED)
> 
>     # Data target
>     @data_target = FXDataTarget.new()
> 
>     # Widget
>     @data_widget = FXTextField.new(frame, 5, @data_target,
> FXDataTarget::ID_VALUE) 
> 
>     # We put some data into the data target
>     @data_target.value = 123
> 
>     # We add a message handler
>     #@data_widget.connect(SEL_KEYPRESS) do |sender, selector, data|  
>     #    puts d.code #    false
>     #end
> 
>   end
> 
>   def create
>     super
>     show(PLACEMENT_SCREEN)
>   end
> 
> end
> 
> if __FILE__ == $0
>   application = FXApp.new("Attik System", "FXRuby Test")  
>   MyWindow.new(application) application.create
>   application.run
> end

Hi again,

I understand more or less what happens here. The link between the data target and the widget works here:

----------------------------------------
#!/usr/bin/ruby

require 'fox16'

include Fox

class MyWindow < FXMainWindow
    
  def initialize(app)

    super(app, "Window", nil, nil, DECOR_ALL, 0, 0, 200, 100)

    # Menu bar stretched along the top of the main window
    menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
  
    # File menu
    filemenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&File", nil, filemenu)
    FXMenuCommand.new(filemenu, "&Quit\tCtl-Q\tQuit the application",
        nil, app, FXApp::ID_QUIT)

    # Frames
    frame = FXMatrix.new(self, 4,
        LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_THICK|FRAME_RAISED)

    # Data target
    @data_target = FXDataTarget.new()
    
    # Widget
    #@data_widget = FXTextField.new(frame, 5, @data_target, FXDataTarget::ID_VALUE)
    @data_widget = FXTextField.new(frame, 5)
    
    # We put some data into the data target
    @data_target.value = 123

    # We add a message handler
    @data_widget.connect(SEL_KEYPRESS) do |sender, selector, data|
        puts data.code
        0
    end
    
    # We connect the data target to the widget
    @data_widget.target = @data_target
    @data_widget.selector = FXDataTarget::ID_VALUE

  end

  def create
    super
    show(PLACEMENT_SCREEN)
  end

end

if __FILE__ == $0
  application = FXApp.new("Attik System", "FXRuby Test")
  MyWindow.new(application)
  application.create
  application.run
end
----------------------------------------


But here it does not:

----------------------------------------
#!/usr/bin/ruby

require 'fox16'

include Fox

class MyWindow < FXMainWindow
    
  def initialize(app)

    super(app, "Window", nil, nil, DECOR_ALL, 0, 0, 200, 100)

    # Menu bar stretched along the top of the main window
    menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
  
    # File menu
    filemenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&File", nil, filemenu)
    FXMenuCommand.new(filemenu, "&Quit\tCtl-Q\tQuit the application",
        nil, app, FXApp::ID_QUIT)

    # Frames
    frame = FXMatrix.new(self, 4,
        LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_THICK|FRAME_RAISED)

    # Data target
    @data_target = FXDataTarget.new()
    
    # Widget
    #@data_widget = FXTextField.new(frame, 5, @data_target, FXDataTarget::ID_VALUE)
    @data_widget = FXTextField.new(frame, 5)
    
    # We put some data into the data target
    @data_target.value = 123
    
    # We connect the data target to the widget
    @data_widget.target = @data_target
    @data_widget.selector = FXDataTarget::ID_VALUE

    # We add a message handler
    @data_widget.connect(SEL_KEYPRESS) do |sender, selector, data|
        puts data.code
        0
    end

  end

  def create
    super
    show(PLACEMENT_SCREEN)
  end

end

if __FILE__ == $0
  application = FXApp.new("Attik System", "FXRuby Test")
  MyWindow.new(application)
  application.create
  application.run
end
----------------------------------------


To say things briefly, we have to connect the data target to it's widget AFTER we have added our first handler. Otherwise the link between the data target and the widget gets deleted:

The problem comes from here:

----------------------------------------
module Responder2
  #
  # Assign a "handler" for all FOX messages of type _messageType_
  # sent from this widget. When called with only one argument,
  # a block is expected, e.g.
  #
  #     aButton.connect(SEL_COMMAND) { |sender, selector, data|
  #       ... code to handle this event ...
  #     }
  #
  # The arguments passed into the block are the _sender_ of the
  # message (i.e. the widget), the _selector_ for the message, and
  # any message-specific _data_.
  #
  # When #connect is called with two arguments, the second argument
  # should be some callable object such as a Method or Proc instance, e.g.
  #
  #     aButton.connect(SEL_COMMAND, method(:onCommand))
  #
  # As with the one-argument form of #connect, the callable object
  # will be "called" with three arguments (the sender, selector and
  # message data).
  #
  def connect(messageType, callableObject=nil, &block)
    unless instance_variables.include?('@pseudoTarget')
      @pseudoTarget = Fox::FXPseudoTarget.new
      self.target = @pseudoTarget
    end
    @pseudoTarget.pconnect(messageType, callableObject, block)
  end
End
----------------------------------------


When calling

    @data_widget.connect(SEL_KEYPRESS) do |sender, selector, data|
        puts data.code
        0
    end

... A pseudoTarget is being created, and the target starts pointing at it.


I don't know how to handle that. For now, I have just added an exception, like this:

----------------------------------------
module Responder2
  #
  # Assign a "handler" for all FOX messages of type _messageType_
  # sent from this widget. When called with only one argument,
  # a block is expected, e.g.
  #
  #     aButton.connect(SEL_COMMAND) { |sender, selector, data|
  #       ... code to handle this event ...
  #     }
  #
  # The arguments passed into the block are the _sender_ of the
  # message (i.e. the widget), the _selector_ for the message, and
  # any message-specific _data_.
  #
  # When #connect is called with two arguments, the second argument
  # should be some callable object such as a Method or Proc instance, e.g.
  #
  #     aButton.connect(SEL_COMMAND, method(:onCommand))
  #
  # As with the one-argument form of #connect, the callable object
  # will be "called" with three arguments (the sender, selector and
  # message data).
  #
  def connect(messageType, callableObject=nil, &block)
    unless instance_variables.include?('@pseudoTarget')
      
      # We check if another target is already registered.
      # This might be true for a widget already linked to an
      # FXDataTarget object.
      if self.target
        raise "A target is already registered for this object."
      end
      
      @pseudoTarget = Fox::FXPseudoTarget.new
      self.target = @pseudoTarget
    end
    @pseudoTarget.pconnect(messageType, callableObject, block)
  end
End
----------------------------------------



Cheers,

---------------
Philippe Lang
Attik System

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 3125 bytes
Desc: not available
Url : http://rubyforge.org/pipermail/fxruby-users/attachments/20061007/1909ede3/attachment.bin 


More information about the fxruby-users mailing list