繁体   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