Philippe Lang
2006-Oct-07 12:15 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
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 --------------- 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/1b2af216/attachment-0001.bin
Philippe Lang
2006-Oct-07 15:26 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
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 > endHi 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
Jeroen van der Zijp
2006-Oct-10 14:59 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
On Saturday 07 October 2006 07:15, Philippe Lang 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?Do the same for the SEL_KEYRELEASE and it will work.... - Jeroen
Philippe Lang
2006-Oct-10 16:17 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
Jeroen van der Zijp wrote:> On Saturday 07 October 2006 07:15, Philippe Lang 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? > > Do the same for the SEL_KEYRELEASE and it will work....Hi, I''m convinced it is not the problem: under FXRuby, message handling has been implemented using "PseudoTargets", in order to simplify the way you write message handlers. Connecting a handler to a widget changes its target (the new target is the pseudo target!). So if you previously set the target of widget to an FXDataTarget, the link gets lost after you connect the handler. This makes FXDataTarget objects pretty useless under FXRuby... --------------- 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/20061010/b4c40f4c/attachment-0001.bin
Joel VanderWerf
2006-Oct-10 22:15 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
Philippe Lang wrote:> This makes FXDataTarget objects pretty useless under FXRuby...Have you looked at FoxTails/Observable? FoxTails subclasses some of the Fox/FXRuby classes and defines an initialize method that (typically) takes an object and an attribute name instead of the usual target arguments. The attribute name is used to keep that attr in sync when the widget is used. FoxTails uses Fox''s #connect mechanism for this functionality (typically, using SEL_COMMAND, SEL_FOCUSOUT, etc) rather than data targets. This means you can still use connect (with other messages) for other purposes. You can also use the #when_foo methods to register blocks of code to execute when the attr changes or matches a pattern. Here''s a simple combobox example that lets you select an object (in terms of its string representation using #inspect) and then changes a label to display the class of the object. #!/usr/bin/env ruby require ''foxtails'' include Fox include FoxTails class ComboWindow < FXMainWindow observable :items, :selected def initialize(*args) super self.items = [:foo, "Bar", String, 3, ["a", "b"], 1.23] self.selected = items[3] FXStatusBar.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER) mb = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X) file_menu = FXMenuPane.new(self) FXMenuTitle.new(mb, "&File", nil, file_menu) FXMenuCommand.new(file_menu, "&Quit\tCtl-Q\tQuit the application."). connect(SEL_COMMAND) { getApp().exit } combo = FTComboBox.new(self, 20, self, :items, :selected, COMBOBOX_STATIC|FRAME_THICK) def combo.display(item); item.inspect; end label = FXLabel.new(self, "") when_selected CHANGES do label.setText("Class of item is #{selected.class}") end end def create super show end end class ComboApp < FTApp def initialize super("Combo", "TEST") FoxTails.get_standard_icons ComboWindow.new(self, "Combo") end end ComboApp.new.run -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
Philippe Lang
2006-Oct-11 06:37 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
fxruby-users-bounces at rubyforge.org wrote:>> This makes FXDataTarget objects pretty useless under FXRuby... > > Have you looked at FoxTails/Observable? FoxTails subclasses > some of the Fox/FXRuby classes and defines an initialize > method that (typically) takes an object and an attribute name > instead of the usual target arguments. The attribute name is > used to keep that attr in sync when the widget is used. > > FoxTails uses Fox''s #connect mechanism for this functionality > (typically, using SEL_COMMAND, SEL_FOCUSOUT, etc) rather than > data targets. This means you can still use connect (with > other messages) for other purposes. You can also use the > #when_foo methods to register blocks of code to execute when > the attr changes or matches a pattern. > > Here''s a simple combobox example that lets you select an > object (in terms of its string representation using #inspect) > and then changes a label to display the class of the object. > > #!/usr/bin/env ruby > > require ''foxtails''... Thanks Joel, I have to check your library. Otherwise, Lyle, do you think it would be possible to implement messaging in FXRuby differently, without the FXPseudoTarget? I''m wondering why the content of the FXPseudoTarget class cannot be included directly, at run-time, in the object itself, rather than in in a separate class. This would avoid modifying the target of an object when connecting a handler to it. class FXPseudoTarget < FXObject include Responder @@targets_of_pending_timers = {} @@targets_of_pending_chores = {} @@targets_of_pending_signals = {} @@targets_of_pending_inputs = {} # # Returns an initialized FXPseudoTarget object. # def initialize super @blocks = {} end # # Store an association between a message of type # _messageType_ with a callable object or a block. # def pconnect(messageType, callableObject, block) if callableObject.nil? @blocks[messageType] = block else @blocks[messageType] = callableObject end FXMAPTYPE(messageType, :onHandleMsg) case messageType when SEL_TIMEOUT @@targets_of_pending_timers[self] = self when SEL_CHORE @@targets_of_pending_chores[self] = self when SEL_SIGNAL @@targets_of_pending_signals[self] = self when SEL_IO_READ, SEL_IO_WRITE, SEL_IO_EXCEPT @@targets_of_pending_inputs[self] = self end end # # Handle a message from _sender_, with selector _sel_ and # message data _ptr_. # def onHandleMsg(sender, sel, ptr) messageType = Fox.FXSELTYPE(sel) result = @blocks[messageType].call(sender, sel, ptr) case messageType when SEL_TIMEOUT @@targets_of_pending_timers.delete(self) when SEL_CHORE @@targets_of_pending_chores.delete(self) end result end end --------------- 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/20061011/dfdd7ae7/attachment.bin
Lyle Johnson
2006-Oct-11 14:51 UTC
[fxruby-users] Data Targets and message handlers [was: Default double-click in FXTable?]
On Oct 10, 2006, at 11:17 AM, Philippe Lang wrote:> I''m convinced it is not the problem: under FXRuby, message handling > has been implemented using "PseudoTargets", in order to simplify > the way you write message handlers. Connecting a handler to a > widget changes its target (the new target is the pseudo target!). > So if you previously set the target of widget to an FXDataTarget, > the link gets lost after you connect the handler. > > This makes FXDataTarget objects pretty useless under FXRuby...Unless I''m misunderstanding what it is that you''re trying to do, this has nothing to do with FXRuby. A FOX widget (such a FXTextField) can only have a single message target. That target object can be an FXDataTarget, or it can be some other object that responds to messages, but there can only be one. You can''t (directly) connect an FXTextField to, say, both an FXDataTarget and some other object that handles SEL_KEYPRESS and SEL_KEYRELEASE messages sent from the FXTextField.