2016-04-30 1 views
0

У меня есть служба JavaFX, и я хочу получать уведомление через обратный вызов, когда Служба обновляет настраиваемое свойство. Как правило, это делается так: сервис имеет некоторые встроенные свойства, такие как «состояние», «workDone», «value» и т. Д. Наиболее похожим на тот, который я хочу подражать, является свойство «value» named. Свойство «значение» определяется как класс обслуживания.Прослушивание SimpleListProperty <T> обновления из службы JavaFX

private final ObjectProperty<V> value = new SimpleObjectProperty<>(this, "value"); 
    @Override public final V getValue() { checkThread(); return value.get(); } 
    @Override public final ReadOnlyObjectProperty<V> valueProperty() { checkThread(); return value; } 


In my case I needed to listen to updates to a pair of message objects being updated by my JavaFX service thread, so I added a custom named property for each one as shown below. 

    // add 'heartbeat' bound property 
    private final ObjectProperty<CAServiceHeartbeatMessage> heartbeat = 
     new SimpleObjectProperty<>(this, "heartbeat", null);  
    public CAServiceHeartbeatMessage getHeartbeat() { 
     return heartbeat.get(); 
    } 
    public void setHeartbeatMessage(CAServiceHeartbeatMessage aHeartbeat) { 
     heartbeat.set(aHeartbeat); 
    } 
    public ObjectProperty<CAServiceHeartbeatMessage> heartbeatProperty() { 
     return heartbeat; 
    } 

    // add 'memberSystemStatus' bound property 
    private final ObjectProperty<MemberSystemStatusMessage> memberSystemStatus = 
     new SimpleObjectProperty<>(this, "memberStatus", null); 
    public MemberSystemStatusMessage getMemberStatus() { 
     return memberSystemStatus.get(); 
    } 
    public void setMemberSystemMessage(MemberSystemStatusMessage aMemberSystemStatus) { 
     memberSystemStatus.set(aMemberSystemStatus); 
    } 
    public ObjectProperty<MemberSystemStatusMessage> memberSystemStatusProperty() { 
     return memberSystemStatus; 
    }  

Тогда в классе контроллера я добавил следующий код для обновления графического интерфейса на основе изменений каждого из этих свойств:

// heartbeatMessageProperty listener 
// Update the GUI widgets when a new CAServiceHeartbeatMessage (heartbeatMessage) is updated 
mListenerService.heartbeatProperty().addListener(
    (ObservableValue<? extends CAServiceHeartbeatMessage> observer, 
    CAServiceHeartbeatMessage oldValue, CAServiceHeartbeatMessage newValue) -> { 
    // this is where we need to intelligently update the appropriate 
    // heartbeat service entries 
    System.out.println("updated CAServiceHeartbeatMessage"); 
}); 

// 'memberSystemMessage' bound property listener 
mListenerService.memberSystemStatusProperty().addListener(
    (ObservableValue<? extends MemberSystemStatusMessage> observer, 
    MemberSystemStatusMessage oldValue, MemberSystemStatusMessage newValue) -> { 
    if (newValue == null) { 

. , ,

Мой вопрос в том, как заменить несколько SimpleObjectProperties на использование одного SimpleListProperty s или SimpleMapProperty в моем классе JavaFX Service. Я не уверен, как, или мне нужно следовать некоторому соглашению об именовании свойств, чтобы выставить в моем потоке какое-то простое свойство списка, как это было сделано с двумя специфическими и отдельно названными свойствами. Возможно, стоит отметить, что эти сообщения имеют общий базовый класс сообщений - поэтому они могут храниться в простом типе списка. Я также хотел бы увидеть пример того, как я могу обрабатывать обновления, чтобы обновлять графический интерфейс при возникновении изменений, в частности, я не знаю, как определить, какой из элементов в списке или карте изменился.

ответ

2

Для прослушивания изменений элементов в списке, вы можете инициализировать ObservableList с этим методом заводской FXCollections:

ObservableList<Message> messages = FXCollections.observableArrayList(message -> new Observable[] { message.messageProperty() }); 

Создает новый пустой наблюдаемый список подкреплённого ArrayList. В этом списке представлены обновления элементов.

или:

FXCollections.observableList(backingList, message -> new Observable[] { message.messageProperty() }); 

Создаёт ObservableList, подкрепленная указанного списка. Операции мутации экземпляра ObservableList будут сообщены наблюдателям, зарегистрированным в этом экземпляре. Обратите внимание, что операции мутации, сделанные непосредственно в базовом списке, не сообщаются наблюдателям любого ObservableList, который его обертывает. В этом списке также перечислены мутации элементов в нем с помощью экстрактора. Наблюдаемые объекты, возвращаемые экстрактором (применяются к каждому элементу списка), прослушиваются для изменений и преобразуются в «обновление» изменения ListChangeListener.

javadoc

public void changeListener() { 

     ObservableList<Message> messages = FXCollections.observableArrayList(message -> new Observable[] { message.messageProperty() }); 

     messages.addListener((ListChangeListener<Message>) c -> { 

      while (c.next()) { 
       LOGGER.debug("change: {}", c); 

       if (c.wasAdded()) { 
        List<? extends Message> addedSubList = c.getAddedSubList(); 
       } 
       if (c.wasUpdated()) { 
        int from = c.getFrom(); 
        int to = c.getTo(); 
        List<? extends Message> subList = c.getList().subList(from, to); 
       } 
      } 
     }); 

     HearBeat beat = new HearBeat("beat"); 

     messages.add(beat); 
     messages.add(new Status("status")); 

     beat.setMesssage("beat changed"); 
     beat.setMesssage("beat changed again"); 

     messages.addAll(new Status("1"), new Status("2")); 
    } 

    public abstract class Message { 

     private StringProperty message; 

     Message(String message) { 
      this.message = new SimpleStringProperty(message); 
     } 

     public StringProperty messageProperty() { 
      return message; 
     } 

     public String getMesssage() { 
      return message.get(); 
     } 

     public void setMesssage(String val) { 
      message.set(val); 
     } 
    } 

    public class HearBeat extends Message { 

     public HearBeat(String message) { 
      super(message); 
     } 
    } 

    public class Status extends Message { 

     Status(String message) { 
      super(message); 
     } 
    } 
+0

спасибо за подробный ответ, я новичок в Java 8 потоков и лямбды - Я не понимаю, что происходит в сообщении -> новый Наблюдаемые [] {сообщение .messageProperty()} его странный синтаксис и довольно запутанный. Также мои объекты сообщений не могут быть изменены, чтобы содержать StringProperty - они эффективно структурируются с использованием Javolution, поэтому я не могу изменить их размер. Как применить свой пример к публичному классу MyService extends Service {...} в моем случае внутри класса У меня есть два отдельных объекта SimpleObjectProperties, которые я хотел бы объединить в ObservableArrayList? – johnco3

+1

Если вам не нужно слушать изменения элементов внутри ваших объектов сообщений, вы можете использовать 'ListChangeListener', как показано выше. Поместите ваши сообщения в «ObservableList», параметризованные с типом вашего базового класса сообщений и присоедините слушателя.'ObservableList messages = FXCollections.observableArrayList(); messages.addAll (status1, status2, beat1, beat2); messages.addListener (...); ' – jns

+1

Это позволит вам увидеть изменения, внесенные в список сообщений, например. добавьте бит, удалите статус, но вы не увидите изменений, внесенных в сам элемент списка. Для этого используется экстрактор заводского метода. Он прикрепляет слушателя к указанному вами свойству, например. messageProperty(): 'FXCollections.observableArrayList (message -> new Observable [] {message.messageProperty()})' – jns