madmuffin
madmuffin

Reputation: 993

Double binding: Model <-> Bean <-> JavaFX

Considering I have the following three classes:

Model:

class Field {
    private String label;
}

Bean:

class FieldBean {
    public FieldBean(Field f) { this.field = f};
    private Field field;
    private SimpleStringProperty label = new SimpleStringProperty();
    public String getLabel() { return label.get(); }
}

JavaFX Application:

class MyApp extends Application {
    public void start(Stage stage) {
        Label lblTest = new Label();
        FieldBean fieldBean = new FieldBean(model.getField());
        Bindings.bindBidirectional(fieldBean.getLabel(), label.textProperty());
    }
}

What I am trying to achieve is to have the Label updated, whenever i change the Field label. From what I know of this model binding so far, I need to add a PropertyChangeListener, but I haven't got a clue, where about it should be attached. My guess would be in the FieldBean. (and my model already has property change support, just stripped it for better readability).

Upvotes: 0

Views: 177

Answers (2)

James_D
James_D

Reputation: 209225

You can use a JavaBeanStringProperty, which is basically an adapter between a JavaFX StringProperty and a bound JavaBeans property. For example:

class FieldBean {

    private final StringProperty label ;
    private final Field field;

    public FieldBean(Field f) { 
        this.field = f;
        label = JavaBeanStringPropertyBuilder.create()
            .bean(this.field)
            .name(label)
            .build();
    public String getLabel() { return label.get(); }
    public StringProperty labelProperty() { return label ; }
    public void setLabel(String label) { this.label.set(label); }
}

then (assuming you have property change listeners set up for Field.label), Field.label and FieldBean.label will automatically be bound.

As Tomas points out, you don't need both of these classes as they effectively represent exactly the same thing. You can omit the Field class as Tomas shows, or, if your Field class already exists as part of a data representation that's already written, you can just use the JavaBeanStringProperty as an adapter to bind directly to a bound JavaBean property:

Field field = new Field();

// ...

Label uiLabel = new Label();
uiLabel.textProperty().bind(JavaBeanStringPropertyBuilder.create()
    .bean(field)
    .name(label)
    .build());

Calling field.setLabel(...) now automatically changes uiLabel's text. In this example the FieldBean class is omitted entirely.

Upvotes: 1

Tomas Mikula
Tomas Mikula

Reputation: 6537

If FieldBean.field.label and FieldBean.label.get() are meant to represent the same value, then there is no need to have them both.

class FieldBean {
    private StringProperty label;

    public FieldBean(String label) {
        this.label = new SimpleStringProperty(label);
    }

    public StringProperty labelProperty() { return label; }
    public String getLabel() { return label.get(); }
}

Then, to keep a Label updated, you just do

label.textProperty().bind(fieldBean.labelProperty());

Notice that the class Field is omitted altogether.

Upvotes: 0

Related Questions