2017-01-11 8 views
0

カスタムコンポーネントTableBlockを作成しました。 LabelとTableViewで構成されています。 TableViewには、たとえば、1〜1000行があります。行数は、FXMLファイルのパラメータ "rowsFromPrefs"によって定義されます。このパラメータは、TableViewの作成に必要です。 TableViewは、JAVAコードによって完全に作成されています.fxmlはタグとパラメータであり、いくつかの行があります。カスタムjavafxコンポーネントのパラメータとしてカスタムFXMLプロパティを設定します

私が知っているように、JavaFXはFXMLコンポーネントを構築するとき、最初にコンストラクタを呼び出し、次に@FXML注釈付きフィールドを呼び出し、initialize()メソッドを開始します。

私の場合、initialize()が開始されると、変数rowsFromPrefsはまだnullです!しかし、もし私が他のスレッド(JavaFXランチャーではない)からrowsFromPrefsの値を取得しようとすると、定義されていることがわかります。

私は、JavaがFXMLファイルからオブジェクトのパラメータをどの瞬間に割り当てるのか分からない。 fxmlファイルからオブジェクトにパラメータを渡すにはどうすればいいですか?

コンストラクタパラメータに@NamedArgアノテーションが見られました。オブジェクトが作成されているときにパラメータを渡す唯一の方法ですか?

コントローラが一度に呼び出される初期化()メソッド、>その関連ドキュメントの内容>が完全にロードされた実装コントローラ定義できる:

TableBlock.java

public class TableBlock extends VBox{ 
    @FXML 
    private String rowsFromPrefs; 
    @FXML 
    private Label label; 

public TableBlock() { 
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("TableBlock.fxml")); 
    fxmlLoader.setRoot(this); 
    fxmlLoader.setController(this); 
    try { 
     fxmlLoader.load(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

@FXML 
public void initialize() { 
    this.table = createTable(rowsFromPrefs); 
} 

public String getRowsFromPrefs() { 
    System.out.println("getRowsFromPrefs"); 
    return rowsFromPrefs; 
} 


public void setRowsFromPrefs(String rowsFromPrefs) { 
    this.rowsFromPrefs = rowsFromPrefs; 
} 

}

TableBlock.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.*?> 
<?import ru.laz.model.controls.*?> 
<?import java.lang.*?> 
<?import javafx.scene.layout.*?> 
<?import javafx.scene.layout.AnchorPane?> 
<?import ru.laz.model.controls.tableblock.*?> 


<fx:root type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> 
    <children> 
     <Label text="Label" /> 
    </children> 
</fx:root> 

View.java

public class View extends Application { 
Parent root = null; 
private Scene scene; 

@Override 
    public void init() { 
    try { 
      root = FXMLLoader.load(getClass().getResource("View.fxml")); 
      root.requestLayout(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
} 

@Override 
    public void start(final Stage stage) throws Exception { 
    scene = new Scene(root, 640, 480, Color.LIGHTGRAY); 
    stage.show(); 
} 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

View.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import java.lang.*?> 
<?import javafx.scene.layout.*?> 
<?import javafx.scene.control.*?> 
<?import ru.laz.model.controls.tableblock.*?> 


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> 
    <children> 
     <TableBlock rowsFromPrefs="2" id="IDDQD"/> 
    </children> 
</AnchorPane> 

答えて

1

まず、rowsFromPrefs@FXML注釈が何の目的を果たすされていないことに注意してください。 @FXML現在のオブジェクトがコントローラであるFXMLファイルに、フィールド名に一致する値のfx:id属性を持つ要素がある場合、フィールドに値が挿入されます。 TableBlock.fxmlにはfx:id="rowsFromPrefs"という要素がないため、この注釈は何も実行していません。

View.fxmlをロードしているFXMLLoader<TableBlock>要素を検出すると、そのコンストラクタを呼び出してTableBlockインスタンスを作成します。次に、属性で指定された値を設定します。だからあなたのFXML要素

<TableBlock rowsFromPrefs="2" id="IDDQD"/> 

はもちろん

TableBlock tableBlock = new TableBlock(); 
tableBlock.setRowsFromPrefs("2"); 
tableBlock.setId("IDDQD"); 

と本質的に同等である、TableBlockのコンストラクタは、単にコードが何を言っているん:それはFXMLLoaderを作成し、ルートとコントローラを設定し、そのためFXMLLoaderを入力し、load()を呼び出します。のロードプロセスは、FXMLLoaderのコントローラー(コンストラクターが実行されているオブジェクトのTableBlock)にフィールドを設定してからinitialize()を呼び出します。

initialize()は、コンストラクタにあるFXMLLoader.load()の呼び出しの一部として呼び出されます。もちろん、これはすべてsetRowsFromPrefs("2");が呼び出される前に発生します。

ので要約すると、TableBlock.initialize()TableBlock.fxmlが解析された後に呼び出され、そこに定義された任意の要素は、対応する@FXML -annotatedフィールドに注入したが、View.fxmlがロードされる前に発生します。

この問題を解決する1つの方法は、rowsFromPrefsTableBlockコンストラクタに渡すことです。これを行うには、@NamedArg annotationを使用する:あなたはfxmlLoader.load()を呼び出す前に、必要に応じて

public class TableBlock extends VBox{ 

    private final String rowsFromPrefs; 

    @FXML 
    private Label label; 

    public TableBlock(@NamedArg("rowsFromPrefs") String rowsFromPrefs) { 

     this.rowsFromPrefs = rowsFromPrefs ; 
     FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("TableBlock.fxml")); 
     fxmlLoader.setRoot(this); 
     fxmlLoader.setController(this); 
     try { 
      fxmlLoader.load(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @FXML 
    public void initialize() { 
     this.table = createTable(rowsFromPrefs); 
    } 

    public String getRowsFromPrefs() { 
     System.out.println("getRowsFromPrefs"); 
     return rowsFromPrefs; 
    } 


} 

今すぐFXMLであなたの属性は、コンストラクタに代わりの設定メソッドに渡されますので、rowsFromPrefsは、初期化されます。

他のオプションは、コードをinitialize()メソッドからsetRowsFromPrefs(...)メソッドに移動するだけです。 TableBlockインスタンスごとにrowsFromPrefsを修正し、個々のTableBlockインスタンスのライフサイクル中にrowsFromBlocksを変更できるようにする場合にのみ、2番目のオプションを使用するようにする場合は、上記のオプションを使用します。

+0

詳細な説明はありがとうございます。私は思いますが、NamedArgは適切な解決策です。 – LazerJet

関連する問題