2016-04-30 7 views
0

Ich habe einen JavaFX-Service SimpleListProperty und ich möchte über einen Rückruf benachrichtigt werden, wenn der Dienst eine benutzerdefinierte Eigenschaft aktualisiert. Normalerweise ist die Art und Weise dies geschehen ist, dass der Dienst einige in Eigenschaften wie „Staat“ aufgebaut „workDone“, „Wert“ usw. Die eine am meisten ähnlich dem ich nacheifern wollen, ist der „Wert“ benannte Eigenschaft. Die Eigenschaft "value" ist in der Serviceklasse wie folgt definiert.Zuhören <T> Updates von einem JavaFX-Service

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; 
    }  

Dann in der Controller-Klasse habe ich den folgenden Code, um die GUI auf Änderungen an jede dieser Eigenschaften basiert zu aktualisieren:

// 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) { 

. . .

Meine Frage ist, wie kann ich mehrere SimpleObjectProperties ersetzen, um eine einzige SimpleListProperty s oder SimpleMapProperty in meiner JavaFX Service-Klasse zu verwenden. Ich bin mir nicht sicher, wie oder ob ich einer Namenskonvention für Eigenschaften folgen muss, um eine einfache Listeneigenschaft in meinem Thread verfügbar zu machen, so wie ich es mit den 2 spezifischen und separat benannten Nachrichteneigenschaften getan habe. Es ist wahrscheinlich erwähnenswert, dass diese Nachrichten eine gemeinsame Basis-Nachrichtenklasse teilen - so könnten sie in einem einfachen Listentyp gespeichert werden. Ich möchte auch ein Beispiel sehen, wie ich den Updates behandeln könnte, damit ich die GUI aktualisieren, wenn die Änderungen auftreten, insbesondere ich don'w wissen, wie die der Elemente in der Liste, um zu bestimmen oder geändert kartieren.

Antwort

2

auf Änderungen der Elemente in Ihrer Liste zu hören, können Sie die ObservableList mit dieser Factory-Methode von FXCollections initialisieren:

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

Erzeugt eine neue leere beobachtbaren Liste von einem Arraylist gesichert. Diese Liste enthält Elementupdates.

oder:

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

Konstruiert einen ObservableList, die von der angegebenen Liste unterstützt wird. Mutationsoperationen in der ObservableList-Instanz werden Beobachtern gemeldet, die sich in dieser Instanz registriert haben. Beachten Sie, dass Mutation Operationen direkt auf die zugrunde liegende Liste gemacht sind nicht auf Beobachter jegliche ObservableList berichtet, dass es umschließt. In dieser Liste werden auch Mutationen der Elemente durch Verwendung von Extraktor angezeigt. Observable-Objekte, die vom Extraktor zurückgegeben werden (auf jedes Listenelement angewendet), werden auf Änderungen überwacht und in "Update" -Wechsel von ListChangeListener umgewandelt.

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

Dank für die ausführliche Antwort, ich bin neu in Java 8-Streams und Lambda-Ausdrücke - ich nicht wirklich verstehen, was in Botschaft los ist -> neue Observable [] {Nachricht .messageProperty()} ist eine seltsame Syntax und eher verwirrend. Auch meine Nachrichtenobjekte können nicht so geändert werden, dass sie eine StringProperty enthalten - sie sind effektiv Strukturen, die Javolution verwenden, so dass ich ihre Größe nicht ändern kann. Wie würde ich Ihr Beispiel zu einer öffentlichen Klasse MyService erweitert Service- {...} in meinem Fall innerhalb der Klasse gelten habe ich die 2 separaten SimpleObjectProperties den Ich mag würde in eine ObservableArrayList verschmelzen? – johnco3

+1

Wenn Sie nicht auf Änderungen der Elemente in Ihrer Nachricht Objekte hören müssen, können Sie einen 'ListChangeListener' verwenden, wie ich oben zeigte. Setzen Sie Ihre Nachrichten in eine "ObservableList", die mit dem Typ Ihrer Basis-Nachrichtenklasse paramterisiert ist, und hängen Sie den Listener an.'ObservableList messages = FXCollections.observableArrayList(); messages.addAll (status1, status2, beat1, beat2); messages.addListener (...); ' – jns

+1

Dadurch können Sie Änderungen sehen, die an der Nachrichtenliste vorgenommen werden, z. Fügen Sie Beat hinzu, entfernen Sie den Status, aber Sie sehen keine Änderungen am Listenelement selbst. Dafür wird der Extraktor der Factory-Methode verwendet. Es verbindet einen Listener mit der Eigenschaft, die Sie angeben, z. the messageProperty(): 'FXCollections.observableArrayList (Nachricht -> new Observable [] {message.messageProperty()})' – jns