Можно ли создать свойство, которое прослушивает изменения пользовательских объектов в javafx?

Предположим, у меня есть класс сущности Foo, который содержит некоторые поля, геттеры, сеттеры и конструктор. Например:

public class Foo {
private Integer a = 0;
private Integer b = 0;

public Foo() {
}

public Integer getA() {
    return a;
}

public void setA(Integer a) {
    this.a = a;
}

public Integer getB() {
    return b;
}

public void setB(Integer b) {
    this.b = b;
}
}

Затем я хочу знать, когда изменяется a или b. Я знаю, что в javaFX есть ObjectProperty. Итак, я создаю свойство объекта:

ObjectProperty<Foo> fooProperty = new SimpleObjectProperty<>(new Foo());

Затем, чтобы знать об изменениях полей a и b, я добавляю ChangeListener:

fooProperty.addListener((observable, oldValue, newValue) -> {
    System.out.println("Property changed!");
});

Затем эксперименты:

fooProperty.set(new Foo());

работает хорошо, но следующая строка:

fooProperty.get().setA(10)

не вызывает прослушиватель. Причина этого ясна. Последняя строка фактически не меняет объект Foo (ссылка остается прежней).

У меня есть несколько возможных решений. Но все они недостаточно элегантны. Например, изменение каждого поля как свойства и добавление одного и того же прослушивателя для каждой переменной.

Итак, вопрос. Как добавить прослушиватель изменений полей пользовательского объекта?


person Nazarii Mediukh    schedule 20.06.2017    source источник
comment
Разве это не решается путем реализации a и b как IntegerProperty и использования фиксированного экземпляра Foo? Или я неправильно понимаю вопрос?   -  person James_D    schedule 20.06.2017


Ответы (1)


не знаю, хотите ли вы этого или нет, вы можете взять это для справки.

Сначала я создаю класс, его функция — нести информацию.

public class EventObj{
  private String message;
  private Object newObj;

  public EventObj(String msg, Object obj){
    this.message = msg;
    this.newObj = obj;
  }

  public String getMessage(){
    return this.message;
  }

  public Object getNewObj(){
    return this.newObj;
  }
}

затем создайте класс Foo, у него есть два поля Object, мы будем слушать, если они изменятся.

public class Foo{
  private SimpleObjectProperty<Object> a;
  private SimpleObjectProperty<Object> b;

  private SimpleObjectProperty<EventObj> out;


  public Foo(){
    a = new SimpleObjectProperty<>();
    b = new SimpleObjectProperty<>();
    out = new SimpleObjectProperty<>();
    initEvent();
  }

  private void initEvent(){
    a.addListener(new ChangeListener<Object>(){
      @Override
      public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue){
        out.set(new EventObj("a changed", newValue));
      }
    });

    b.addListener(new ChangeListener<Object>(){
      @Override
      public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue){
        out.set(new EventObj("b changed", newValue));
      }
    });
  }

  public void setA(Object a){
    this.a.set(a);
  }

  public void setB(Object b){
    this.b.set(b);
  }

  public SimpleObjectProperty<EventObj> outProperty(){
    return out;
  }
}

в другом классе, используя приведенный ниже код, чтобы прослушивать изменения a или b в foo.

Foo foo = new Foo();
foo.outProperty().addListener(new ChangeListener<EventObj>(){
  @Override
  public void changed(ObservableValue<? extends EventObj> observable, EventObj oldValue, EventObj newValue){
    System.out.println(newValue.getMessage() + ", new value is : " + newValue.getNewObj());
  }
});

foo.setA(new Object());
foo.setB(new Object());

в этом случае мы просто используем класс Object, если вы хотите использовать пользовательский класс для замены, не забудьте переопределить его методы hashCode() и equals(), чтобы определить, являются ли два объекта одинаковыми.

person yab    schedule 20.06.2017
comment
Спасибо, это лучше, чем все возможности, которые у меня были. - person Nazarii Mediukh; 21.06.2017
comment
@NazariiMediukh пожалуйста, я рад помочь вам. - person yab; 21.06.2017