I am trying to format an integer while binding it to the text property of a label.
I know I can use setText() in my value setter, but I'd rather do it the proper way through binding.
In my controller initialization I had:
sec = new SimpleIntegerProperty(this,"seconds");
secondsLabel.textProperty().bind(Bindings.convert(sec));
But when the number of seconds dropped below 10, it showed as a single digit, but I want it to stay as two digits. So I tried changing the Binding to the following:
secondsLabel.textProperty().bind(Bindings.createStringBinding(() -> {
NumberFormat formatter = NumberFormat.getIntegerInstance();
formatter.setMinimumIntegerDigits(2);
if(sec.getValue() == null) {
return "";
}else {
return formatter.format(sec.get());
}
}));
This will format it, but when I overwrite it sec.set(newNumber);
the value doesn't change.
I also tried this:
secondsLabel.textProperty().bind(Bindings.createStringBinding(() -> {
if(sec.getValue() == null) {
return "";
}else {
return String.format("%02d", sec.getValue());
}
}));
But that did the same thing. Loads up fine, shows two digits, but when the number was changed via sec.set(newNumber);
nothing changed. The number will never go higher than sixty or lower than zero
You need to tell your binding that it should be invalidated any time the sec
property is invalidated. Bindings.createStringBinding(...)
takes a varargs parameter after the function that should be passed any properties to which the binding needs to bind. You can directly adapt your code as follows:
secondsLabel.textProperty().bind(Bindings.createStringBinding(() -> {
NumberFormat formatter = NumberFormat.getIntegerInstance();
formatter.setMinimumIntegerDigits(2);
if(sec.getValue() == null) {
return "";
}else {
return formatter.format(sec.get());
}
}, sec));
or
secondsLabel.textProperty().bind(Bindings.createStringBinding(() -> {
if(sec.getValue() == null) {
return "";
}else {
return String.format("%02d", sec.getValue());
}
}, sec));
As @fabian points out, IntegerProperty.get()
never returns null, so you can remove the null check and just do:
secondsLabel.textProperty().bind(Bindings.createStringBinding(
() -> String.format("%02d", sec.getValue()),
sec));
and there is a convenience version of this in the bindings API:
secondsLabel.textProperty().bind(Bindings.format("%02d", sec));