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
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…