Apply LongProperty to TableColumn programmatically (vs semantically)

ぐ巨炮叔叔 提交于 2019-12-12 03:35:45

问题


(Following this question, this is what prompted it)

I have a model class with a LongProperty:

public class Model { 
    private final SimpleLongProperty number = new SimpleLongProperty(this, "number"); 
    public long getNumber() { return number.get(); }
    public void setNumber(long number) { this.number.set(number); }
    public LongProperty numberProperty() { return number; }
}

Now, in my controller I have a TableColumn<Model, Long> colNumber which I want to bind to this property. I know I can use PropertyValueFactory, but I don't like the idea of giving the property by name when I can pass it programmatically, and have the compiler/ide spell-check me. Basically I want to do something like this (I actually want to make it more concise, example in the end):

colNumber.setCellValueFactory( cdf -> cdf.getValue().numberProperty() );

but this gives me a compilation error:

java: incompatible types: bad return type in lambda expression javafx.beans.property.ObjectProperty cannot be converted to javafx.beans.value.ObservableValue

As I said, I know I can use PropertyValueFactory, and also have static final strings for the property names, but I find it less elegant. Is there a way to make this programmatic approach work? Some casting-magic?

Appendix:
The actual way I wanted to make it is with a helper method:

private <S,T> Callback<CellDataFeatures<S,T>, ObservableValue<T>> propertyFactory(Callback<S, ObservableValue<T>> callback) {
    return cdf-> callback.call(cdf.getValue());
}

and then I can just use

colNumber.setCellValueFactory(propertyFactory(Model::numberProperty));

which keeps my code very concise and readable, and has the compiler checking me for typos etc.


回答1:


You can do

colNumber.setCellValueFactory( cdf -> cdf.getValue().numberProperty().asObject() );

I think (I'd need to test, but this seems right) you could also take advantage of autoboxing and unboxing in your model, and implement the property as an ObjectProperty<Long>:

public class Model { 
    private final ObjectProperty<Long> number = new SimpleObjectProperty<>(this, "number", 0L); 
    public long getNumber() { return number.get(); }
    public void setNumber(long number) { this.number.set(number); }
    public ObjectProperty<Long> numberProperty() { return number; }
}

One disadvantage to this approach is it would not allow any of the arithmetic bindings, e.g. you couldn't do someValue.bind(model.numberProperty().multiply(2)); etc. (Another is that you could call model.numberProperty().set(null); by accident, and wreak all kinds of havoc.)

One other solution, of course, is to make your table column a TableColumn<Model, Number>, but there may be other reasons not to do that.

FWIW, I would definitely advocate avoiding PropertyValueFactory. That was a convenience class introduced in JavaFX 2.0 (i.e. before we had lambdas), when it was very verbose to implement the callback that allowed for compiler checking. Now it is basically redundant (and should be deprecated, imho, or should at least implement a utility method of the kind you outline).



来源:https://stackoverflow.com/questions/34621485/apply-longproperty-to-tablecolumn-programmatically-vs-semantically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!