将自定义FXML属性设置为自定义javafx组件的参数

时间:2017-01-11 15:43:39

标签: java javafx fxml

我创建了自定义组件TableBlock。它由Label和TableView组成。例如,TableView可以有1到1000行。行数由FXML文件中的参数“rowsFromPrefs”定义。创建TableView需要此参数。 TableView完全由JAva代码创建,fxml只是它的标记和带有多行的参数。

据我所知,当JavaFX构造FXML组件时,它首先调用构造函数,然后调用@FXML注释字段,然后启动initialize()方法。

在初始化()开始的情况下,变量rowsFromPrefs仍为空!但是,如果我试图从其他线程(而不是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>

1 个答案:

答案 0 :(得分:3)

首先,请注意@FXML上的rowsFromPrefs注释没有用处。当当前对象为控制器的FXML文件具有@FXML属性且其值与字段名称匹配的元素时,fx:id会为字段注入值。由于TableBlock.fxml没有fx:id="rowsFromPrefs"的元素,因此此注释没有执行任何操作。

当正在加载FXMLLoader的{​​{1}}遇到View.fxml元素时,它会通过调用其构造函数创建一个<TableBlock>实例。然后它将设置属性指定的值。所以你的FXML元素

TableBlock

基本上等同于

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

当然,TableBlock tableBlock = new TableBlock(); tableBlock.setRowsFromPrefs("2"); tableBlock.setId("IDDQD"); 的构造函数只执行代码所要做的事情:它创建TableBlock,为FXMLLoader设置根和控制器,然后调用{{ 1}}。 FXMLLoader的加载过程将在控制器(构造函数正在执行的load()对象)上设置FXMLLoader注入的字段,然后调用{{ 1}}。

因此,@FXML作为TableBlock构造函数中initialize()调用的一部分进行调用;当然这一切都发生在调用initialize()之前。

总而言之,FXMLLoader.load()在解析TableBlock之后调用,并且在那里定义的任何元素都会注入到相应的setRowsFromPrefs("2"); - 注释字段中,但这发生在{{1}之前已加载。

解决此问题的一种方法是将TableBlock.initialize()传递给TableBlock.fxml构造函数。为此,请使用@NamedArg annotation

@FXML

现在,FXML中的属性将传递给构造函数而不是set方法,因此在您根据需要调用View.fxml之前,将初始化rowsFromPrefs

当然,另一个选项只是将代码从TableBlock方法移动到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; } } 方法。如果您打算为每个rowsFromPrefs实例修复fxmlLoader.load(),我会使用上述选项,并且仅当您希望能够在生命周期中更改initialize()时才使用第二个选项个人setRowsFromPrefs(...)实例。