FXDataTarget not updating my variable

I have the following:

@datatarget = FXDataTarget.new(@name)
@datatarget.connect(SEL_COMMAND) do |s,i,data|
puts "#{data},#{@name}"
end
# ... in another class ...
FXTextField.new(parent,80,obj.datatarget,FXDataTarget::ID_VALUE)
l = FXLabel.new(parent,"foo")
l.target = obj.datatarget
l.selector = FXDataTarget::ID_VALUE

The label updates correctly. If it starts out as ‘foo’, and I change it
to ‘bar’ and press enter in the FXTextField, this is what is printed:

bar,foo

But I was under the impression that a datatarget would update the
variable as it was changed. Is that wrong? If not, why is this
happening? I can of course set @name in the connect block but that seems
silly since that’s the whole point of a data target, or so I thought.

···


Hans Fugal | De gustibus non disputandum est.
http://hans.fugal.net/ | Debian, vim, mutt, ruby, text, gpg
http://gdmxml.fugal.net/ | WindowMaker, gaim, UTF-8, RISC, JS Bach

GnuPG Fingerprint: 6940 87C5 6610 567F 1E95 CB5E FC98 E8CD E0AA D460

Hans Fugal wrote:

But I was under the impression that a datatarget would update the
variable as it was changed. Is that wrong? If not, why is this
happening?

Generally speaking, SEL_CHANGED messages are usually sent while a
widget’s value is changing, and SEL_COMMAND when it is “finished”. So,
for example, an FXSlider widget will send SEL_CHANGED messages
continously to its target while you’re dragging the slider back and
forth, but will only send SEL_COMMAND to its target when you stop
dragging and release the mouse button. In the same way, an FXTextField
sends SEL_CHANGED to its target every time the text field’s contents
changes (e.g. by adding or removing a character), but it only sends
SEL_COMMAND when you press or tab out of the text field.

So try modifying the previous snippet from this:

 @datatarget.connect(SEL_COMMAND) do |s,i,data|
puts "#{data},#{@name}"
 end

to this:

 @datatarget.connect(SEL_CHANGED) do |s,i,data|
puts "#{data},#{@name}"
 end

and see if you get the result you expected.

Hope this helps,

Lyle

Hi Lyle,

Generally speaking, SEL_CHANGED messages are usually sent while a
widget’s value is changing, and SEL_COMMAND when it is “finished”.
I was aware of what you are talking about, and I actually only want it
to happen on SEL_COMMAND (when the user presses enter). In that respect
it is behaving as I expect (the when), but it is not updating @name like
I expected. (the what)

I wrote a little test to demonstrate what’s happening. As the comment
says inline, I expected the datatarget to change the value of the
variable, but it does not. (That’s what the Fox docs seem to indicate
should be happening, at least in my mind.)

#!/usr/bin/env ruby
require ‘fox’
include Fox
class DataTargetWindow < FXMainWindow
def initialize(app)
super(app, “Data Targets Test”, nil, nil, DECOR_ALL, 20, 20, 200, 100)

@foo = "foo"
dt = FXDataTarget.new(@foo)

vframe = FXVerticalFrame.new(self)
frame = FXHorizontalFrame.new(vframe)

l = FXLabel.new(frame,"B")
l.target = dt
l.selector = FXDataTarget::ID_VALUE
FXTextField.new(frame,10,dt,FXDataTarget::ID_VALUE)

FXButton.new(vframe,"puts").connect(SEL_COMMAND) do
    # I expected @foo and dt.value to be the same, but they will be
    # different if the value has changed in the textfield.
    puts "#{@foo},#{dt.value}" 
end

show
end

end
if FILE == $0
application = FXApp.new(“DataTarget”, “FoxTest”)
window = DataTargetWindow.new(application)
application.create
application.run
end

···


Hans Fugal | De gustibus non disputandum est.
http://hans.fugal.net/ | Debian, vim, mutt, ruby, text, gpg
http://gdmxml.fugal.net/ | WindowMaker, gaim, UTF-8, RISC, JS Bach

GnuPG Fingerprint: 6940 87C5 6610 567F 1E95 CB5E FC98 E8CD E0AA D460

Hans Fugal wrote:

I was aware of what you are talking about, and I actually only want it
to happen on SEL_COMMAND (when the user presses enter). In that respect
it is behaving as I expect (the when), but it is not updating @name like
I expected. (the what)

I wrote a little test to demonstrate what’s happening. As the comment
says inline, I expected the datatarget to change the value of the
variable, but it does not. (That’s what the Fox docs seem to indicate
should be happening, at least in my mind.)

Oh, no, that’s not how the Ruby version of FXDataTarget works. For
FXRuby, you need to work directly with the data target’s value, i.e.
setting it:

 dt.value = "spam"

or reading it back:

 puts "current value is #{dt.value}"

You are correct that this is different from the C++ implementation,
because in C++ the data target actually stores a C++ reference to the
variable of interest. We can’t do that in Ruby, since some of the
primitive object types (namely, integers and floats) are immutable objects.

If this is too restrictive for your application, you might want to check
out some work that Joel VanderWerf has done with his FoxTails extension
for FXRuby (http://raa.ruby-lang.org/list.rhtml?name=foxtails). It takes
advantage of the “observable” module (another of Joel’s creations) to
allow you to connect GUI components to observable attributes. This is a
potentially much more powerful approach and it may offer the kind of
solution you’re looking for.

Hope this helps,

Lyle

Oh, no, that’s not how the Ruby version of FXDataTarget works. For
FXRuby, you need to work directly with the data target’s value, i.e.
setting it:

dt.value = "spam"

or reading it back:

puts "current value is #{dt.value}"

You are correct that this is different from the C++ implementation,
because in C++ the data target actually stores a C++ reference to the
variable of interest. We can’t do that in Ruby, since some of the
primitive object types (namely, integers and floats) are immutable objects.
Ok, that makes sense. I’m glad I’m not losing it. :wink: This could be
better documented.

If this is too restrictive for your application, you might want to check
out some work that Joel VanderWerf has done with his FoxTails extension
for FXRuby (http://raa.ruby-lang.org/list.rhtml?name=foxtails). It takes
advantage of the “observable” module (another of Joel’s creations) to
allow you to connect GUI components to observable attributes. This is a
potentially much more powerful approach and it may offer the kind of
solution you’re looking for.
Looks very interesting. Indeed this is exactly the sort of thing we are
doing.

···

Lyle Johnson lyle@users.sourceforge.net wrote:


Hans Fugal | De gustibus non disputandum est.
http://hans.fugal.net/ | Debian, vim, mutt, ruby, text, gpg
http://gdmxml.fugal.net/ | WindowMaker, gaim, UTF-8, RISC, JS Bach

GnuPG Fingerprint: 6940 87C5 6610 567F 1E95 CB5E FC98 E8CD E0AA D460

Hans Fugal wrote:

If this is too restrictive for your application, you might want to check
out some work that Joel VanderWerf has done with his FoxTails extension
for FXRuby (http://raa.ruby-lang.org/list.rhtml?name=foxtails). It takes
advantage of the “observable” module (another of Joel’s creations) to
allow you to connect GUI components to observable attributes. This is a
potentially much more powerful approach and it may offer the kind of
solution you’re looking for.

Looks very interesting. Indeed this is exactly the sort of thing we are
doing.

Hans, here’s how I’d write your original example using FoxTails:

···

Lyle Johnson lyle@users.sourceforge.net wrote:

==========================
#!/usr/bin/env ruby

require ‘fox’
require ‘foxtails’

include Fox
include FoxTails

class DataTargetWindow < FXMainWindow
include Observable

observable :foo

def initialize(app)
super(app, “Data Targets Test”, nil, nil, DECOR_ALL, 20, 20, 200, 100)

 self.foo = "foo" # NOTE: "@foo = ..." will not trigger updates

 vframe = FXVerticalFrame.new(self)
 frame = FXHorizontalFrame.new(vframe)

 l = FXLabel.new(frame,"B")
 tf = FTTextField.new(frame,10,self,:foo)

 tf.dynamic = true # assuming you want foo updated while you are editing

 when_foo CHANGES do
   l.text = foo
 end

 FXButton.new(vframe,"puts").connect(SEL_COMMAND) do
   puts foo
 end

 show

end
end

if FILE == $0
application = FXApp.new(“DataTarget”, “FoxTest”)
window = DataTargetWindow.new(application)
application.create
application.run
end

If you don’t want the label to change while you are editing, just remove
the “tf.dynamic = true”.

Note that “when_foo” is not limited to the initialize method. You can
set up observers from other methods, or even other objects:

window = DataTargetWindow.new(application)
window.when_foo CHANGES do |new_foo| … end

Also, CHANGES is just a synonym for Object. You can use anything with an
#=== method, including regexes. The match is attempted whenever the attr
writer is called.

It would be possible to define a class FTLabel which lets you “tie” the
label to a given observable attr, much like FTTextField works. However,
it’s easy enough to achieve the same effect with a “when” clause and the
#text= accessor. Also, one principle of foxtails is that the initialize
method of FXFooBar and FTFooBar are the same except for replacing the
“tgt,sel” with an object (or a proc returning an object) and the name of
an observable attr in that object. FXLabel doesn’t have tgt,sel in its
initialize, so there’s no parallel over in foxtails land. Anyway,
dynamically changing labels are kind of unusual.

Let me know if you have questions with FoxTails…