簡體   English   中英

將自定義FXML屬性設置為自定義javafx組件的參數

[英]Set custom FXML properties as parameters for custom javafx component

我創建了自定義組件TableBlock。 它由Label和TableView組成。 TableView可以具有例如1到1000行。 行數由FXML文件中的參數“ rowsFromPrefs”定義。 創建TableView時需要此參數。 TableView是完全由JAva代碼創建的,在fxml中只是其標記和帶有多行的參數。

據我所知,當JavaFX構造FXML組件時,它首先調用構造函數,然后調用@FXML帶注釋的字段,然后啟動initialize()方法。

在我的情況下,當initialize()啟動時,變量rowsFromPrefs仍然為null! 但是,如果我嘗試從其他線程(而不是JavaFX-launcher)中獲取rowsFromPrefs的值,我會看到它像應該那樣定義為“ 2”。

所以我不明白Java在什么時候從FXML文件分配對象參數。 創建參數時,如何將參數從fxml文件傳遞給對象。

我看到了@NamedArg注釋的構造函數參數。 它是創建對象時傳遞參數的唯一方法嗎?

控制器可以定義一個initialize()方法,當其關聯文檔的內容已完全加載時,將在實現控制器上調用一次:

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>

首先,注意@FXML上標注rowsFromPrefs是服務沒有任何意義。 @FXML使待注射的值的字段時的量,當前對象是控制器的FXML文件具有與一個元件fx:id屬性,它的值的字段名稱相匹配。 由於TableBlock.fxml沒有帶有fx:id="rowsFromPrefs"元素,因此此注釋不執行任何操作。

FXMLLoader正在加載View.fxml遇到<TableBlock>元素,它創建一個TableBlock通過調用它的構造實例。 然后它將設置屬性指定的值。 因此,您的FXML元素

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

基本上等於

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

當然,對於構造TableBlock少了點什么碼說的事:它創造了FXMLLoader ,設置根和控制器為FXMLLoader ,然后調用load() 加載過程FXMLLoader將設置@FXML -injected控制器(在上字段TableBlock對象,其構造為執行),然后調用initialize()

因此,在對TableBlock構造函數中的TableBlock initialize()進行調用的過程中,調用了FXMLLoader.load() 當然,這一切都發生在setRowsFromPrefs("2");之前setRowsFromPrefs("2"); 被調用。

因此,總而言之,在解析TableBlock.fxml之后,將調用TableBlock.initialize() ,並將其中定義的任何元素注入其相應的@FXML字段中,但這是在加載View.fxml之前發生的。

解決此問題的一種方法是將rowsFromPrefs傳遞給TableBlock構造函數。 為此,請使用@NamedArg批注

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中的屬性將傳遞給構造函數,而不是傳遞給set方法,因此在需要調用fxmlLoader.load()之前, rowsFromPrefs進行初始化。

當然,另一個選擇就是將代碼從initialize()方法移到setRowsFromPrefs(...)方法。 如果您打算為每個TableBlock實例固定rowsFromPrefs ,那么我將使用上述選項,並且僅當您希望能夠在單個TableBlock實例的生命周期內更改rowsFromBlocks時,才使用第二個選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM