简体   繁体   中英

Why does FXMLLoader not initialize fields when a field is declared as a super-type

When I declare a field player as shown below:

class Controller{
    @FXML Shape player;
}

.fxml file - <Rectangle fx:id="player"...\>
Where in the Controller , player is declared as a super type ( Shape ), and in the fxml file it is declared as a subtype.

I declare player as Shape , instead of Rectangle , because I have multiple similar fxml files, and the program decides, during runtime, which one to load. Every fxml file has a player object of some child class of Shape

My problem is that when a field is declared as the super type, fxml loader doesn't initialize that field. I would like to know a work-around to this problem.

A minimum reproducible example:

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class test2 extends Application {
    @FXML Shape player;
    public void start(Stage stage) throws Exception
    {
        Scene scene = new Scene(
                FXMLLoader.load(getClass().getResource("t.fxml"))
        );
        stage.setTitle("JavaFX Example");
        stage.setScene(scene);
        stage.show();
        System.out.println(player); //prints null
    }
    public static void main (String [] args){
        launch(args);
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.shape.Rectangle?>
<Pane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
    <Rectangle fx:id="player" x="20" y="20" width="40" height="40"/>
</Pane>

@FXML -annotated fields are initialized in the controller. Typically to create controllers, you specify a fx:controller attribute in the root element of the FXML (though there are other ways to do this). Your test2 class [sic] is not the controller class (and even if it were, the instance on which start() is invoked would not be the controller).

The following modification of your code demonstrates that fields declared as a superclass type are indeed initialized as you would expect:

Controller.java:

package org.jamesd.examples.supertype;

import javafx.fxml.FXML;
import javafx.scene.shape.Shape;

public class Controller{
    @FXML Shape player;
    
    public void initialize() {
        System.out.println(player);
    }
}

t.fxml (note fx:controller attribute):

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

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.shape.Rectangle?>
<Pane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0"
    prefWidth="600.0"
    fx:controller="org.jamesd.examples.supertype.Controller">
    <Rectangle fx:id="player" x="20" y="20" width="40" height="40" />
</Pane>

Test2.java:

package org.jamesd.examples.supertype;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class Test2 extends Application {
    @FXML Shape player;
    public void start(Stage stage) throws Exception
    {
        Scene scene = new Scene(
                FXMLLoader.load(getClass().getResource("t.fxml"))
        );
        stage.setTitle("JavaFX Example");
        stage.setScene(scene);
        stage.show();
    }
    public static void main (String [] args){
        launch(args);
    }
}

This generates the expected output:

Rectangle[id=player, x=20.0, y=20.0, width=40.0, height=40.0, fill=0x000000ff]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM