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 !
JavaFX properties are often used in conjunction with binding, a powerful mechanism for expressing direct relationships between variables. When objects participate in bindings, changes made to one object will automatically be reflected in another object. This can be useful in a variety of applications.
If you want to erase the content of the label, do: final Label result = ... root. add(result, 0, 1); button.
The JavaFX binding synchronizes two values: when a dependent variable changes, the other variable changes. To bind a property to another property, call the bind() method which binds values in one direction.
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.
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