2016-04-30 26 views
0

我有一個JavaFX服務,並希望在服務更新自定義屬性時通過回調得到通知。通常,這樣做的方式是該服務具有一些內置的屬性,如「狀態」,「workDone」,「價值」等。最想與我想模仿的是名爲「value」的屬性。 「value」屬性在服務類中定義如下。收聽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; 
    }  

然後在控制器類添加以下代碼來更新基於變化到每個這些屬性的GUI:

// 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在我的JavaFX服務類中使用單個SimpleListPropertySimpleMapProperty。我不知道如何,或者是否需要遵循一些屬性命名約定來公開我的線程中的一些簡單的列表屬性,就像我使用2個特定的和單獨命名的消息屬性一樣。 IT可能值得注意的是,這些消息共享一個通用的基類消息類 - 因此它們可以存儲在一個簡單的列表類型中。我還希望看到一個示例,說明如何處理更新,以便在更改發生時更新GUI,特別是我不知道如何確定列表或映射中的哪些元素髮生了更改。

回答

2

要收聽您的列表中元素的變化,你可以用FXCollections此工廠方法initalize的ObservableList

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流和lambda表達式 - 我真的不明白是什麼在消息回事 - >新的可觀測[] {消息.messageProperty()}它的一個奇怪的語法,而相當混亂。此外,我的消息對象不能修改爲包含StringProperty - 它們是使用Javolution的有效結構,因此我無法更改它們的大小。我將如何將您的示例應用到公共類MyService extends Service {...}在我的情況下在類中我有2個單獨的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 [] {m​​essage.messageProperty()})' – jns