Tokee's

Get notified when working with JavaFX properties

When working with JavaFX properties most of us are interested in notifications about value changes. Getting notified about any of these changes can be realised by applying a ChangeListener or an InvalidationListener. We’re fine so far, aren’t we?
(In case of you’re not familiar with using JavaFX properties, start with reading Using JavaFX Properties and Binding at Oracle’s website.)

Have a look at the following example:

package propertyexample;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class PropertyExample {

    private StringProperty value;

    public PropertyExample() {
        this.value = new SimpleStringProperty(this, "value");
    }

    public StringProperty getValueProperty() {
        return this.value;
    }
    
    public final void setValue(String stringValue) {
        this.value.set(stringValue);
    }
    
    public final String getValue() {
        return this.value.get();
    }
    
    public static void main(String[] args) {
        final PropertyExample example = new PropertyExample();
        
        example.getValueProperty().addListener(new InvalidationListener() {

            @Override
            public void invalidated(Observable o) {
                StringProperty property = (StringProperty)o;
                System.out.println("current value: " + property.getValue());
            }
        });
              
        //assign String instance with a value of 'a' and fire InvalidationListener
        example.setValue(new String("a")); 
        //assign String instance with a value of 'a' and nothing will happen
        example.setValue(new String("a"));
    }
}

As you might have expected the applied InvalidationListener will only fire once, since new String("a").equals(new String("a")) => true. This is fine for most cases, but what when you’re interested in getting notified when any value is assigned and expect the InvalidationListener firing everytime a value is assigned, even if the new value equals the previously assigned one. I spent much time and tried many different ways

  • extending the SimpleStringProperty
  • implementing a new StringProperty and
  • fallback to good old listeners

All of these ways lead to a working solution, but the expense of time and lines of code is beyond any comparison with my finally working solution. This one is as simple as just exchanging the StringProperty with an ObjectProperty<String>. This works since value comparison and marking as invalid is implemented differently in SimpleStringProperty and SimpleObjectProperty<String>.

package propertyexample;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

public class PropertyExample {
    
    private ObjectProperty<String> value;
    
    public PropertyExample() {
        this.value = new SimpleObjectProperty<String>(this, "value");
    }
    
    public ObjectProperty<String> getValueProperty() {
        return this.value;
    }
    
    public final void setValue(String stringValue) {
        this.value.set(stringValue);
    }
    
    public final String getValue() {
        return this.value.get();
    }
    
    public static void main(String[] args) {
        final PropertyExample example = new PropertyExample();
        
        example.getValueProperty().addListener(new InvalidationListener() {
            
            @Override
            public void invalidated(Observable o) {
                ObjectProperty<String> property = (ObjectProperty<String>) o;
                System.out.println("current value: " + property.get());
            }
        });
        
        //assign String instance with a value of 'a' and fire InvalidationListener
        example.setValue(new String("a"));
        //assign String instance with a value of 'a' and fire InvalidationListener
        example.setValue(new String("a"));
    }
}

Just a note: To get notified you have to assign different references. Assigning the same reference as shown in the following example only results in firing the InvalidationListener once.

String a = new String("a");
example.setValue(a);
example.setValue(a);

But this shouldn’t be a hurlde ;)

Kommentare sind deaktiviert.