2014-10-28 53 views
1

我想傳遞一個字符串變量列表到自定義控制器FXML,即:返回值並不如預期

<Pane xmlns:fx="http://javafx.com/fxml" > 
    <VBox fx:id="vbox"> 
     <StepChart fx:id="employment" title="Unemployment" enabled = "true" prefHeight="250.0" prefWidth="300.0"> 
      <statistics> 
      <FXCollections fx:factory="observableArrayList" > 
       <String fx:value="employees"/> 
       <String fx:value="farms"/> 
      </FXCollections> 
      </statistics> 
     </StepChart> 
    </VBox> 
    </Pane> 

統計數據將被標記爲StepChart的@DefaultProperty,但爲了完整而包括在這裏。在StepChart我拿起觀察到列表中的值如下:

ArrayList<String> list = new ArrayList<String>(); 
ObservableList<String> statistics = FXCollections.observableArrayList(list); 

statistics.addListener(new ListChangeListener<String>() 
    { 
    @Override 
    public void onChanged(ListChangeListener.Change<? extends String> change) 
    {   
     for(String s: statistics) 
     { 
      System.out.println("s: " + s); 
     } 
    } 
    }); 

所有在它完美的作品,除了不是單獨的字符串列表中,FXML正在生成一個字符串,與FXML值:

s: [employees, farms] 

即使Introduction to fxml說,它「創建一個可觀察的數組列表的一個實例,填充了三個字符串值」。我是否錯過了關於如何處理observablelist的問題,或者這是否是預期的行爲?

+1

'StepChart'有'setStatistics(列表)'方法,還是'getStatistics()'? – 2014-10-29 20:54:28

+0

呃。就是這樣 - 非常感謝。 – Lumi 2014-10-30 00:27:39

+0

如果你的'StepChart'類沒有意義,你不需要'setStatistics(...)'方法。我會把所有的東西放在一起作爲實際的答案,因爲其他人可能從這些信息中受益。 – 2014-10-30 00:55:30

回答

2

我懷疑你的StepChart類沒有setStatistics(...)方法。該FXMLLoader將以一種特殊的方式對待這一點,如下所示:

通常,當FXMLLoader遇到的結構,如:

<ClassName fx:id="ref"> 
    <propertyName> 
    <AnotherClass /> 
    </propertyName> 
</ClassName> 

它執行的是轉換爲類似代碼:

ClassName ref = new ClassName(); 
ref.setPropertyName(new AnotherClass()); 

(不是字面意思,它是等價的,但使用反射)。

大多數情況下,如果在指定的類中沒有定義setPropertyName(...),則會拋出異常。

只讀表被視爲一個特殊情況:所以如果ClassName定義List getList() {...}方法,並沒有void setList(List aList) {...}方法,那麼下面仍然有效:

<ClassName fx:id="ref"> 
    <list> 
     <!-- values --> 
    </list> 
</ClassName> 

此的處理,在這個特殊的方式情況下(該屬性的名稱對應於List類型的具有get方法和沒有set方法的屬性),則執行FXMLLoader以下僞代碼:

ClassName ref = new ClassName(); 
for (Object item : itemsDefinedInsideListElement) { 
    ref.getList().add(item); 
} 

其中for循環遍歷<list>元素中定義的所有元素。該是什麼使您能夠做這樣的事情,即使

<HBox> 
    <children> 
    <Label/> 
    <TextField/> 
    </children> 
</HBox> 

HBox沒有setChildren()方法。

所以,你FXML,假設StepChart沒有setStatistics(...)法,FXMLLoader遍歷所有的<statistics>直接子元素,傳遞每一個getStatistics().add(...)調用它創建的StepChart實例。在這種情況下,只有一個子元素,它是ObservableList<String>

FXMLLoader也足夠聰明,可以在運行時計算列表的通用類型(實際上我不知道它是如何實現的)。由於它看到列表預計爲String,並且該元素未解析爲String,因此它會嘗試將其強制爲正確的類型。強制轉換爲String很容易:它只是在創建列表的結果調用toString,並將結果在那麼你最終包含列表中的單個String:即String是含有List調用toString的結果元素「僱員」和「農場」。等效的Java代碼會看起來像

StepChart employment = new StepChart(); 
employment.getStatistics().add(Arrays.asList("employees", "farms").toString()); 

,所以你看到的單個元素"["employees", "farms"]"作爲statistics內容。

對此有兩個修復,您選擇的應取決於您想在StepChart中公開哪些API。您可以添加setStatistics(ObservableList<String>)方法。然後,FXMLLoader將創建該列表,並將其傳遞給該方法。

或者,你可以繼續忽略setStatistics(...)方法(即保持statistics爲只讀列表屬性)和修改FXML到

<StepChart fx:id="employment" ... > 
     <statistics> 
     <String fx:value="employees"/> 
     <String fx:value="farms"/> 
     </statistics> 
    </StepChart> 

,讓您使用FXMLLoader的只讀列表財產機制。

+0

這是一個非常有用的解釋 - 謝謝。知道它如何組合在一起非常有幫助 - 我發現在某些在線文檔中存在某種伏都教元素。 (我曾經想過,它看起來好像試圖強制它,但不知道如何 - 但沒有與類似豆的語義聯繫起來。) – Lumi 2014-10-30 01:44:07

+0

我同意:一般來說「FXMLLoader」的功能相當不幸。有一個[請求改進](https://javafx-jira.kenai.com/browse/RT35522)您可能會爲此投票。這個特定主題在[FXML文檔簡介](http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html#property_setter_elements)中有所介紹。 – 2014-10-30 01:56:56

+0

但是,但是..我喜歡在午夜宰殺山羊:)正式投票。 – Lumi 2014-10-31 01:26:02