2015-05-15 75 views
2

在「Pro JavaFX 8:構建桌面,移動和嵌入式Java客戶端的權威指南」第3章中,一個示例說明了如何直接在FXML文件中指定對象。FXMLLoader工廠方法可以用於用戶定義的類嗎?

在這篇文章的最後,您可以找到完整的FXML文件以及示例中的其他文件。

這是我正在考慮的片段。 sizes字段使用fx:factory屬性來指示必須使用工廠方法Utilities.createList()來創建整數列表,然後使用三個整數填充整數列表。

<sizes> 
    <Utilities fx:factory="createMyCollection"> 
     <Integer fx:value="1"/> 
     <Integer fx:value="2"/> 
     <Integer fx:value="3"/> 
    </Utilities> 
</sizes> 

這裏是Utilities.java:

package projavafx.fxmlbasicfeatures; 

import java.util.ArrayList; 
import java.util.List; 

public class Utilities { 
    public static final Double TEN_PCT = 0.1d; 
    public static final Double TWENTY_PCT = 0.2d; 
    public static final Double THIRTY_PCT = 0.3d; 

    public static List<Integer> createList() { 
     return new ArrayList<>(); 
    } 
} 

我的問題是:涉及到使用這些工廠方法的一般機制是什麼?

我想了解FXMLLoader如何知道需要使用add方法將三個整數添加到創建的對象中。當然,它必須知道List或許也許Collection,但知識指定在哪裏?它是否內置在FXMLLoader中?如果是這樣,那麼如何爲用戶定義的類提供這種工廠方法?

我實際上已經嘗試將它與用戶定義的類一起使用。添加以下代碼段Utilities.java,它創建了一個MyCollection類具有單個方法並且限定Utilities.createMyCollection方法:

public class Utilities { 
    (...) 
    public static class MyCollection { 
     private List<Integer> myList = new LinkedList<>(); 
     public void add(Integer o) { 
      myList.add(o); 
     } 
     public String toString() { 
      return myList.toString(); 
     } 
    } 

    public static MyCollection createMyCollection() { 
    return new MyCollection();  
    } 
    (...) 
}  

當我在FXML文件取代createMyCollection,但是,我得到的消息「 MyCollections沒有默認屬性。將MyCollection內容放置在一個屬性元素中。「

這讓我想知道如何爲用戶定義的類聲明一個默認屬性,以及List已經有一個。

這裏的所有文件(除了上面Utilities.java):

FXMLBasicFeatures.fxml:

<?import javafx.scene.paint.Color?> 
<?import projavafx.fxmlbasicfeatures.FXMLBasicFeaturesBean?> 
<?import projavafx.fxmlbasicfeatures.Utilities?> 
<?import java.lang.Double?> 
<?import java.lang.Integer?> 
<?import java.lang.Long?> 
<?import java.util.HashMap?> 
<?import java.lang.String?> 
<FXMLBasicFeaturesBean name="John Smith" 
         flag="true" 
         count="12345" 
         xmlns:fx="http://javafx.com/fxml/1"> 
    <address>12345 Main St.</address> 
    <foreground>#ff8800</foreground> 
    <background> 
     <Color red="0.0" green="1.0" blue="0.5"/> 
    </background> 
    <price> 
     <Double fx:value="3.1415926"/> 
    </price> 
    <discount> 
     <Utilities fx:constant="TEN_PCT"/> 
    </discount> 
    <sizes> 
     <Utilities fx:factory="createList"> 
      <Integer fx:value="1"/> 
      <Integer fx:value="2"/> 
      <Integer fx:value="3"/> 
     </Utilities> 
    </sizes> 
    <profits> 
     <HashMap q1="1000" q2="1100" q3="1200" a4="1300"/> 
    </profits> 
    <fx:define> 
     <Long fx:id="inv" fx:value="9765625"/> 
    </fx:define> 
    <inventory> 
     <fx:reference source="inv"/> 
    </inventory> 
    <products> 
     <String fx:value="widget"/> 
     <String fx:value="gadget"/> 
     <String fx:value="models"/> 
    </products> 
    <abbreviations CA="California" NY="New York" FL="Florida" MO="Missouri"/> 

</FXMLBasicFeaturesBean> 

FXMLBasicFeaturesBean.java:

package projavafx.fxmlbasicfeatures; 

import javafx.scene.paint.Color; 

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

public class FXMLBasicFeaturesBean { 
    private String name; 
    private String address; 
    private boolean flag; 
    private int count; 
    private Color foreground; 
    private Color background; 
    private Double price; 
    private Double discount; 
    private List<Integer> sizes; 
    private Map<String, Double> profits; 
    private Long inventory; 
    private List<String> products = new ArrayList<String>(); 
    private Map<String, String> abbreviations = new HashMap<>(); 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String getAddress() { 
     return address; 
    } 

    public void setAddress(String address) { 
     this.address = address; 
    } 

    public boolean isFlag() { 
     return flag; 
    } 

    public void setFlag(boolean flag) { 
     this.flag = flag; 
    } 

    public int getCount() { 
     return count; 
    } 

    public void setCount(int count) { 
     this.count = count; 
    } 

    public Color getForeground() { 
     return foreground; 
    } 

    public void setForeground(Color foreground) { 
     this.foreground = foreground; 
    } 

    public Color getBackground() { 
     return background; 
    } 

    public void setBackground(Color background) { 
     this.background = background; 
    } 

    public Double getPrice() { 
     return price; 
    } 

    public void setPrice(Double price) { 
     this.price = price; 
    } 

    public Double getDiscount() { 
     return discount; 
    } 

    public void setDiscount(Double discount) { 
     this.discount = discount; 
    } 

    public List<Integer> getSizes() { 
     return sizes; 
    } 

    public void setSizes(List<Integer> sizes) { 
     this.sizes = sizes; 
    } 

    public Map<String, Double> getProfits() { 
     return profits; 
    } 

    public void setProfits(Map<String, Double> profits) { 
     this.profits = profits; 
    } 

    public Long getInventory() { 
     return inventory; 
    } 

    public void setInventory(Long inventory) { 
     this.inventory = inventory; 
    } 

    public List<String> getProducts() { 
     return products; 
    } 

    public Map<String, String> getAbbreviations() { 
     return abbreviations; 
    } 

    @Override 
    public String toString() { 
     return "FXMLBasicFeaturesBean{" + 
      "name='" + name + '\'' + 
      ",\n\taddress='" + address + '\'' + 
      ",\n\tflag=" + flag + 
      ",\n\tcount=" + count + 
      ",\n\tforeground=" + foreground + 
      ",\n\tbackground=" + background + 
      ",\n\tprice=" + price + 
      ",\n\tdiscount=" + discount + 
      ",\n\tsizes=" + sizes + 
      ",\n\tprofits=" + profits + 
      ",\n\tinventory=" + inventory + 
      ",\n\tproducts=" + products + 
      ",\n\tabbreviations=" + abbreviations + 
      '}'; 
    } 
} 

FXMLBasicFeaturesMain.java:

package projavafx.fxmlbasicfeatures; 

import javafx.fxml.FXMLLoader; 

import java.io.IOException; 

public class FXMLBasicFeaturesMain { 
    public static void main(String[] args) throws IOException { 
     FXMLBasicFeaturesBean bean = FXMLLoader.load(
      FXMLBasicFeaturesMain.class.getResource(
       "/projavafx/fxmlbasicfeatures/FXMLBasicFeatures.fxml") 
     ); 
     System.out.println("bean = " + bean); 
    } 
} 
+0

java.util.List的實現被FXMLLoader視爲一種特殊情況。你的'MyCollection'類是否實現'List'? –

+0

啊,謝謝,那就是我想知道的,如果支持List的話。 'MyCollection'沒有特意實現'List';我想看看是否可以爲任意類添加這種類型的支持。 – user118967

+0

如果它包含一個列表,並且您很高興通過get方法公開整個列表,您仍然可以完成這項工作。當我回到電腦時,我會發佈一個答案,如果它有幫助 –

回答

3

實際上這裏有幾個不同的問題。如您所知,基本用法是FXMLLoader通過JavaBean命名方案查找古典風格的屬性。所以,如果你有一個類

public class Bean { 

    private String text ; 

    public void setText(String text) { 
     this.text = text ; 
    } 

    public String getText() { 
     return text ; 
    } 
} 

然後(因爲班裏有一個默認的,無參數的構造函數),你可以在FXML實例Bean

<Bean> 

,您可以通過調用setText方法引用屬性text可能作爲屬性:

<Bean text="Some text"/> 

或作爲一個屬性元素:

<Bean> 
    <text> 
     <String fx:value="Some text"/> 
    </text> 
</Bean> 

java.util.List的實例得到了特殊處理。如果屬性名稱匹配的只讀List財產:即java.util.List具有get...方法類型的屬性,但沒有set...方法,在FXML子節點將被傳遞到相應的List實例add(...)方法。

所以,如果我們添加這樣一個屬性的Bean

import java.util.List ; 
import java.util.ArrayList ; 

public class Bean { 

    private String text ; 

    private List<String> elements ; 

    public Bean() { 
     this.elements = new ArrayList<>(); 
    } 

    public List<String> getElements() { 
     return elements ; 
    } 

    public void setText(String text) { 
     this.text = text ; 
    } 

    public String getText() { 
     return text ; 
    } 
} 

然後我們可以填充在FXML名單:

<Bean text="Some text"> 
    <elements> 
    <String fx:value="One"/> 
    <String fx:value="Two"/> 
    <String fx:value="Three"/> 
    </elements> 
<Bean> 

你指的另一個問題是「默認屬性」 。

import java.util.List ; 
import java.util.ArrayList ; 

@DefaultProperty("text") 
public class Bean { 

    private String text ; 

    private List<String> elements ; 

    public Bean() { 
     this.elements = new ArrayList<>(); 
    } 

    public List<String> getElements() { 
     return elements ; 
    } 

    public void setText(String text) { 
     this.text = text ; 
    } 

    public String getText() { 
     return text ; 
    } 
} 

現在,如果你指定的子元素:您可以通過使用這個類的@DefaultProperty註釋,並指定屬性的名稱將被視爲默認指定類的默認屬性實例元素<Bean>在FXML,而不指定屬性,那些將被用作默認屬性值:

<Bean> 
    <String fx:value="Some Text"/> 
</Bean> 

將在Bean實例調用setText("Some Text")

當然,你可以結合這些想法,使List實例的默認屬性(這是本質上的佈局容器是如何工作的:Pane定義"children"作爲其默認的屬性):

import java.util.List ; 
import java.util.ArrayList ; 

@DefaultProperty("elements") 
public class Bean { 

    private String text ; 

    private List<String> elements ; 

    public Bean() { 
     this.elements = new ArrayList<>(); 
    } 

    public List<String> getElements() { 
     return elements ; 
    } 

    public void setText(String text) { 
     this.text = text ; 
    } 

    public String getText() { 
     return text ; 
    } 
} 

,現在你可以不要

<Bean text="Some Text"> 
    <String fx:value="One"/> 
    <String fx:value="Two" /> 
    <String fx:value="Three" /> 
</Bean> 

將填充["One", "Two", "Three"]elements列表。

相關問題