Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX: Binding a TextProperty (eg. Label) to a simple Integer

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 !

like image 554
Onon Avatar asked Dec 31 '15 12:12

Onon


People also ask

What are binding properties used for in JavaFX?

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.

How do I remove a label in JavaFX?

If you want to erase the content of the label, do: final Label result = ... root. add(result, 0, 1); button.

How to bind Property in JavaFX?

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.


1 Answers

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.

like image 160
Itai Avatar answered Oct 16 '22 20:10

Itai