In my code, I am interested about listening to changes to a SimpleDoubleProperty
.
Here's the signature for it's addListener method:
public void addListener(ChangeListener<? super Number> listener)
How does a property that fires changes to a Double
value, require it's listener to listen to Number
or one of it's super types?. Shouldn't it be defined like that:
public void addListener(ChangeListener<? extends Double> listener)
An example class that has the property:
HasObservableProperty.java
public class HasObservableProperty {
private final SimpleDoubleProperty progress = new SimpleDoubleProperty();
...
public void addProgressChangeListener(ChangeListener<? super Number> listener) {
progress.addListener(listener);
}
}
And so it goes, I have a listener defined as:
class ProgressBarNotifier implements ChangeListener<Number> {
private final ProgressBar progress_bar;
public ProgressBarNotifier(ProgressBar bar) {
progress_bar = bar;
}
@Override
public void changed(ObservableValue<? extends Number> progress, Number oldValue,
Number newValue) {
progress_bar.setProgress((Double)newValue);
}
}
See how I was forced to cast the changed value to Double
:
progress_bar.setProgress((Double)newValue);
This shouldn't be the case if the addListener
method had the suggested signature.
So, the question is, is SimpleDoubleProperty.addListener
method wrongly declared?
PS: what applies to SimpleDoubleProperty seems to apply to other observables, like SimpleStringProperty.
The simple answer is "because that's how it was done". Note that, as Uluk points out in the comments, you're not forced to cast: you can call doubleValue()
on the Number
reference you receive in the listener method.
There's a pretty complex hierarchy behind DoubleProperty
. The relevant part is that DoubleProperty implements ObservableDoubleValue extends ObservableNumberValue extends ObservableValue<Number>
. ObservableValue<T>
defines an addListener(ChangeListener<? super T>)
method, so DoubleProperty
has to define addListener(ChangeListener<? super Number>)
.
Was this the best way to do it? I actually don't think so: I think it would have been possible to make ObservableNumberValue
generic: ObservableNumberValue<T extends Number> extends ObservableValue<T>
and then ObservableDoubleValue extends ObservableNumberValue<Double>
, at which point the addListener(...)
method would be relaxed to addListener(ChangeListener<? super Double>)
, which is what you're looking for.
There are whole other parts of the hierarchy: Property
, WritableDoubleValue
, WritableNumberValue
, WritableValue
, etc, that may prevent this structure; but at any rate such a change now would be impossible, so we are stuck with what we have whether it's a mistake or whether there's some complex reason it has to be this way that I'm not aware of. It's occasionally annoying, but as pointed out you can always use doubleValue()
.
In many cases like the one you show, you can also use a binding, e.g. progressBar.progressProperty().bind(progress);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With