Is it possible to bind a StringProperty to a POJO's String in JavaFX?


Question

I'm creating an application using JavaFX 2. I intend to isolate the UI from data and logics. Considering that, I have a lot of data objects like this:

public class Entity {
    private String m_Value;
    public Entity(String value) { m_Value = value; }
    public String getValue() { return m_Value; }
    public void setValue(String value) { m_Value = value; }
}

I'm having a hard time creating a binding between the m_Value attribute and the textProperty of a Label, for instance.

Another similar question here suggested people to use JFXtras, however I'm not sure I'm allowed to use that (company restrictions). So I'm trying to find some alternative to that.

My idea would be to use objects to represent all attributes of my data entities, instead of primitive types (int would use Integer and so on). That way, I can take advantage of the pass by reference model of java. Then, in the UI domain, I could create a Property referencing this attribute. But I'm not sure whether this is possible or not.

It it possible to solve this problem using the ObjectProperty class?

Another alternative could be using the JavaBeanProperty family of classes, like JavaBeanStringPropertyBuilder, JavaBeanIntegerPropertyBuilder. Is it possible?

I've tried both ways, but I'm affraid I'm not that experienced in JavaFX yet to solve this. Can anyone help?

I don't want to use StringProperty or IntegerProperty inside my data objects because I don't want any JavaFX dependencies in this package. There is a strong possibility this application becomes an Eclipse plugin and probably JavaFX would be off. This way I can avoid too much rework in the future.

Thanks very much.

1
4
2/28/2014 8:27:28 PM

Accepted Answer

You can obviously set the values in Entity without doing anything except using a listener in JavaFX. If you want to go the other way you can add java.beans.PropertyChangeSupport. It's not in a javafx package.

package bindpojo;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class BindPojo extends Application {
    StringProperty fxString = new SimpleStringProperty();
    StringProperty tmpString = new SimpleStringProperty();

    @Override
    public void start(Stage primaryStage) {
        VBox vbox = new VBox();
        TextField text = new TextField();
        Label label1 = new Label();
        Label label2 = new Label();
        Entity entity = new Entity("");
        vbox.getChildren().addAll(text,label1,label2);
        Scene scene = new Scene(vbox, 300, 200);
        primaryStage.setScene(scene);
        primaryStage.show();

        fxString.bindBidirectional(text.textProperty());

        fxString.addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                entity.setValue(newValue);
                label1.setText(entity.getValue());
            }
        });

        entity.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                tmpString.set(evt.getNewValue().toString());
            }
        });

        label2.textProperty().bind(tmpString);
    }

    public class Entity {
    private String m_Value;
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    public Entity(String value) { m_Value = value; }
    public String getValue() { return m_Value; }
    public void setValue(String value) {
        pcs.firePropertyChange("m_Value", m_Value, value);
        m_Value = value;
    }
    public void addPropertyChangeListener(PropertyChangeListener listener) {
                    pcs.addPropertyChangeListener(listener);
                }
    }
}

You don't really need the tmpString, I just used used it in case you want to have Entity resemble a javafx string property. You could just set the label in the property change listener instead of setting a string property and then binding to it.

4
2/28/2014 10:31:54 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon