问题
The general question: Is there any way to update a label when the value of a simple integer changes ?
I'm talking about simple int's and not stuff like ReadOnlyIntegerWrappers. I've tried the following according to Converting Integer to ObservableValue<Integer> in javafx (I had to change the identifier (is that what it's called ?) of ObservableValue from Integer to String because I couldn't find a way to bind it to the TextProperty otherwise)
I've included my demo code below which somehow seems to result in a NullPointerException at label.textProperty().bind(m.getObsValue());
. The application is written in a MVC-pattern.
Model:
public class Model {
private int value;
private ObservableValue<String> obsInt;
public Model(){
value = 5;
obsInt = new ReadOnlyObjectWrapper<>(value + "");
}
public int getValue(){
return value;
}
public void setValue(int value){
this.value = value;
}
public ObservableValue<String> getObsValue(){
return obsInt;
}
}
Controller:
public class Controller {
private Model m;
private View v;
public Controller(Model m, View v){
this.m = m;
this.v = v;
}
public void handleMouseclick(MouseEvent e){
m.setValue(m.getValue() + 5);
}
public void init(){
v.setOnMouseClicked(this::handleMouseclick);
}
}
View:
public class View extends Region{
private Model m;
private Label label;
public View(Model m)
{
this.m = m;
label.textProperty().bind(m.getObsValue());
label.setLayoutX(200);
label.setLayoutY(200);
paint();
}
public void paint(){
getChildren().clear();
getChildren().addAll(label);
}
@Override
public double computePrefHeight(double width){
return 800;
}
@Override
public double computePrefWidth(double height){
return 600;
}
}
As you might've noticed I'm currently still studying JavaFX. So I probably just missed something stupid. Any advice would be greatly appreciated !
回答1:
Let's start from the end - the exception is because you never initialize label
, so it is null - as simple as that. Using label = new Label();
should solve it.
And now for the bindings - you say you don't want to use IntegerProperty
or ReadOnlyIntegerWrapper
, but rather use a simple int
- that means you have no convenient way of knowing when the value is changed! The label will always contain the initial value of your integer, so you may as well do something like:
label.setText(Integer.toString(m.getValue()));
Instead, I would advise you to do something like
public class Model {
private SimpleIntegerProperty value = new SimpleIntegerProperty(this, "value");
public Model() {
value.set(5);
}
public int getValue(){
return value.get();
}
public void setValue(int value){
this.value.set(value);
}
public IntegerProperty valueProperty(){
return value;
}
}
then you can bind the label's text property using Bindings.convert
:
label.textProperty().bind(Bindings.convert(m.valueProperty()));
this way, whenever the model's value is changed, the label text would automatically reflect this.
As you can see, SimpleIntegerProperty
is nothing to be afraid of! The arguments in the constructor are optional, but recommended - they are the object this property belongs to (this
), and the name of the property ("value"
, in this case). You can also pass the initial value in the constructor, instead of explicitly setting it in your Model
constructor.
来源:https://stackoverflow.com/questions/34546433/javafx-binding-a-textproperty-eg-label-to-a-simple-integer