2017-02-07 5 views
2

У меня есть несколько панелей и холстов JavaFX, которые ссылаются на сложный объект с необходимыми данными, и я хочу, чтобы они перерисовывались при изменении объекта.Как сделать сложный объект наблюдаемым

Это вызовет объект для наблюдения, но какой класс я использую? В JavaFX, по-видимому, в основном есть подклассы ObservableValue, которые переносят значение и позволяют его заменять. Я не хочу менять сложный объект, просто уведомляю слушателей, когда происходят изменения. Я мог бы это сделать, реализовав addListener, но я уверен, что есть подкласс, который делает это для меня уже.

class ComplexObject /* extends SomeObservableClass */ { 
    public int getValue1 { complex calculations... }; 
    public int getValue2 { ... }; 

    public void setNewValue1(int newValue) { ... } 
} 

class ComplexRenderer extends Canvas implements InvalidationListener { 
    private ComplexObject complexObject; 

    public void setComplexObject(ComplexObject complexObject) { 
     this.complexObject = complexObject; 
     complexObject.addListener(this); 
    } 

    public void draw() { ... } 
} 

В каком классе должен применяться ComplexObject? Есть ли что-то, что поддерживает список слушателей и что-то вроде fireValueChangedEvent(), чтобы я мог сообщить об этом всем слушателям?

Все, что я вижу в JavaFX, похоже, ориентировано на свойства, которые здесь не кажутся правильными.

+0

Не совсем уверен, что вы подразумеваете под «не поменять». Я не уверен, если вы имеете в виду подделку всего «ComplexObject» или, возможно, некоторые значения внутри него. Нужно ли выполнять вычисления для 'getValue()' только при его вызове? Или он может быть рассчитан и сохранен до того, как он будет вызван? – Jai

+0

«Невозможно поменять» означает, что я хочу сохранить тот же «ComplexObject», просто изменив значения внутри него. Мне кажется, что «ObjectPropertyBase» и его друзья предназначены для обертки, поэтому вы заменяете весь объект с помощью 'set()', который затем запускает прослушиватели недействительности. Я мог хранить сложные вычисления и показывать результаты как индивидуальные свойства, но первоначальное намерение состояло в том, чтобы просто иметь сложный объект и выполнять вычисления по требованию. – EboMike

+0

Это означает, что мой ответ должен быть близок к тому, что вы ищете. Вы не отслеживаете изменение в ссылке «ComplexObject». Вместо этого вы отслеживаете изменение ссылок на свои внутренние значения (примитивы должны быть в коробке) и объекты. Если вам нужно отслеживать индивидуальное свойство, вам нужно добавить к ним индивидуальный слушатель. В противном случае вы можете выставить 'BooleanProperty', чтобы вы могли прослушивать любые изменения в любом из свойств. Конечно, внутренне вы должны привязать эти свойства к 'BooleanProperty'. – Jai

ответ

3

Не совсем уверен, что вы имели в виду подкачкой, и не совсем уверен, правильно ли я понял.

class ComplexObject { 
    private IntegerProperty value1 = new SimpleIntegerProperty(); 
    private IntegerProperty value2 = new SimpleIntegerProperty(); 
    private BooleanProperty internalChanged = new SimpleBooleanProperty(false); 

    public ComplexObject() { 
     this.internalChanged.bind(Bindings.createBooleanBinding(() -> 
      this.internalChanged.set(!this.internalChanged.get()), this.value1, this.value2)); 
    } 

    public IntegerProperty value1Property() { return this.value1; } 
    public int getValue1() { return this.value1.get(); } 
    public void setValue1(int value) { return this.value1.set(value); } 

    public IntegerProperty value2Property() { return this.value2; } 
    public int getValue2() { return this.value2.get(); } 
    public void setValue2(int value) { return this.value2.set(value); } 

    public void setNewValue1(int newValue) { /* What value is this??? */ } 

    public BooleanProperty internalChangedProperty() { return this.internalChanged; } 
} 

class ComplexRenderer extends Canvas implements InvalidationListener { 
    private ComplexObject complexObject; 

    public void setComplexObject(ComplexObject complexObject) { 
     this.complexObject = complexObject; 
     complexObject.internalChangedProperty().addListener(this); 
    } 
    @Override public void invalidated(Observable observable) { 
     // Something inside complex object changed 
    } 

    public void draw() { ... } 
} 
+0

Спасибо! Я предполагаю, что в упрощенной форме я буду использовать bool для оповещения слушателей и использования регулярных ints и accessors для фактических значений. Вопросы: 1. Означает ли это, что мне нужно переключать bool каждый раз, когда есть изменения? Слушатели IIRC запускаются только при фактическом изменении данных. 2. Это похоже на взломать систему, чтобы заставить ее делать то, что я хочу. Является ли это обычным способом обработки прослушивателей недействительности? – EboMike

+0

@EboMike Ну, технически вы можете реализовать все без библиотеки ObservableValue. В этом случае вам нужно вручную написать свои собственные геттеры/сеттеры и сделать сеттеры изменить логическое поле на true. Если вы следуете моему ответу, привязка (this.internalChanged.bind (Bindings.createBooleanBinding (() -> this.internalChanged.set (true)).value1, this.value2)); ') должен обрабатывать его для вас. Конечно, вам нужно добавить все свойства в это. Внутренне вы можете представить себе как «Bindings.createBooleanBinding()», подписывающийся на список изменений всех свойств. – Jai

+0

Я сделал это, и это сработало! (Ну, я переключаю логическое значение, а не устанавливаю его в true, но то же самое). Я все еще чувствую, что полностью злоупотребляю системой, но она работает, поэтому я не знаю, насколько я должен заботиться. Спасибо! – EboMike

0

Возможно, вы можете ознакомиться с интерфейсом ObjectPropertyBase<T> и классами ObjectPropertyBase<T> и SimpleObjectProperty<T>, который реализует Observable.

Однако вы должны определить, когда ваш объект меняется и логика прослушивания.

Прошу прощения, это всего лишь след работы, но я надеюсь, что это может быть полезно.

+0

Спасибо! Да, я посмотрел на них. Тем не менее, они также реализуют «ObservableValue», и это согласуется с теми, о которых я упоминал в моем вопросе, - они обертывают объект, поэтому я понимаю, что вы должны заменить сам объект внутри обертки, указав, что что-то изменилось , – EboMike

Смежные вопросы