Reputation: 473
I have a question about binding in JavaFX. Let's say I have mapping 1:"Aaa", 2:"Bbb", 3:"Ccc" and so on. What I want is to bind (bidirectional) 2 properties IntegerProperty and StringProperty according to this mapping. How this can be achieved?
UPD: I'll try to describe my use case. I have a class
class A {
IntegerProperty num;
...
}
But in the user interface I want to show not this numerical value but some meaningful string. So I want to add StringProperty numValue
and bind num
and numValue
. In table I'll use numValue
as property for TableColumn. And when user change value of numValue
(via combobox for example) I want num
automatically update.
Upvotes: 1
Views: 7411
Reputation: 6537
I recommend to avoid bidirectional bindings if you can, they are problematic1.
If you really need a bidirectional binding, then you are lucky that one of your types is String
. There is the bindBidirectional method that let's you specify a StringConverter
used to convert between a String
and the other type T
, in your case Integer
.
Map<Integer, String> m = ...;
StringProperty sp = ...;
IntegerProperty ip = ...;
Bindings.bindBidirectional(sp, ip, new StringConverter<Number>() {
@Override
public Integer fromString(String s) {
for(Integer key: m.keySet()) {
if(m.get(key).equals(s)) {
return key;
}
}
return -1; // or whatever makes sense for you
}
@Override
public String toString(Integer i) {
return m.get(i);
}
});
Why this is supported for types String
and T
and not for arbitrary types T
and U
is a mystery for me.
In more general terms, you have two types, T
, U
, and two functions, f: T -> U
and g: U -> T
, and then you want to establish a bidirectional binding between Property<T>
and Property<U>
using these two functions. In the above example, both f
and g
are realized by the StringConverter
(for example, f
is fromString
and g
is toString
). You can establish such a bidirectional binding using ReactFX's Var
s2:
Function<T, U> f = ...;
Function<U, T> g = ...;
Var<T> vt = ...;
Var<U> vu = ...;
Var<U> vu1 = vt.map(f).asVar(u -> vt.setValue(g.apply(u)));
Bindings.bindBidirectional(vu, vu1);
You don't necessarily need f
to be the inverse of g
, i.e. you don't need g(f(x)) = x
, but in order to avoid infinite loop (stack overflow), it better converge quickly, for example f(g(f(x))) = f(x)
, or g(f(g(f(g(f(g(f(x)))))))) = g(f(g(f(g(f(x))))))
or something like that.
1 I realize I just threw this statement in without providing any valid argument.
2 Var
is really just a Property
with some extra methods.
Upvotes: 5