JavaFX Unable To Set Custom Properties

I'm trying to implement custom properties into a custom component for my JavaFX application. I've read some tutorials and all have pointed me in the direction of below.

For some reason, it's not working. IntelliJ isn't liking when I try and set the property values inside of the FXML file and the scene builder doesn't show the property either.

Label Controller:

public class LabelController {

    @FXML
    public Label label;

    // Define a variable to store the property
    private DoubleProperty amountDue = new SimpleDoubleProperty();

    // Define a getter for the property's value
    public final double getAmountDue(){return amountDue.get();}

    // Define a setter for the property's value
    public final void setAmountDue(double value){amountDue.set(value);}

    // Define a getter for the property itself
    public DoubleProperty amountDueProperty() {return amountDue;}

    public void onMouseEntered(MouseEvent mouseEvent) {
        FadeToHoverColour();
    }

    public void onMouseExited(MouseEvent mouseEvent) {
        FadeToDefaultColour();
    }

    public void FadeToHoverColour() {
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(0.2), new KeyValue(label.textFillProperty(), Paint.valueOf("E63700"))));
        timeline.play();
    }

    public void FadeToDefaultColour() {
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(0.2), new KeyValue(label.textFillProperty(), Paint.valueOf("FF774D"))));
        timeline.play();
    }
}

Label.fxml:

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

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="madoc.controllers.components.LabelController">
    <Label fx:id="label"
           text="TEXT"
           onMouseEntered="#onMouseEntered"
           onMouseExited="#onMouseExited">
    </Label>
</VBox>

WelcomeSceneBuilder.fxml:

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

<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="madoc.controllers.scenes.WelcomeSceneController">
    <fx:include source="./Label.fxml" [NOT WORKING WHEN I TRY TO SET AMOUNT DUE HERE]/>
</AnchorPane>

1 answer

  • answered 2019-07-15 13:21 fabian

    The attributes/children added to the <fx:include> element apply to the result of loading the other fxml, i.e. in this case the type of object created is VBox, not LabelController. VBox does not contain the properties you're trying to assign.

    You cannot do this using fxml only. You'd need to use the initialize method of the controller to set the property values:

    WelcomeSceneController

    @FXML
    private LabelController labelController;
    
    @FXML
    private void initialize() {
        labelController.setAmountDue(...);
    }
    

    WelcomeSceneBuilder.fxml

    ...
    <fx:include source="./Label.fxml" fx:id="label"/>
    ...
    

    You could use the Custom Component approach though which would make the controller and node the same object allowing you to make assignments like these. Lacking inso about the responsibility of the node, I'm keeping LabelController, but of course you should choose a better name.

    package madoc.controllers.components;
    
    ...
    
    public class LabelController extends VBox {
    
        public LabelController() {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/madoc/controllers/components/Label.fxml")); // TODO: replace with correct resoure path?
            loader.setRoot(this);
            loader.setController(this);
            try {
                loader.load();
            } catch(IOException ex) {
                throw new IllegalStateException("Could not load fxml file", ex);
            }
        }
    
        @FXML
        public Label label;
    
        // Define a variable to store the property
        private final DoubleProperty amountDue = new SimpleDoubleProperty();
    
        // Define a getter for the property's value
        public final double getAmountDue(){return amountDue.get();}
    
        // Define a setter for the property's value
        public final void setAmountDue(double value){amountDue.set(value);}
    
        // Define a getter for the property itself
        public DoubleProperty amountDueProperty() {return amountDue;}
    
        ...
    }
    

    Label.fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.VBox?>
    
    <fx:root xmlns="http://javafx.com/javafx"
          xmlns:fx="http://javafx.com/fxml"
          type="javafx.scene.layout.VBox">
        <Label fx:id="label"
               text="TEXT"
               onMouseEntered="#onMouseEntered"
               onMouseExited="#onMouseExited">
        </Label>
    </fx:root>
    

    WelcomeSceneBuilder.fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.AnchorPane?>
    <?import madoc.controllers.components.LabelController?>
    
    <AnchorPane xmlns="http://javafx.com/javafx"
                xmlns:fx="http://javafx.com/fxml"
                fx:controller="madoc.controllers.scenes.WelcomeSceneController">
        <LabelController amountDue="30.05"/>
    </AnchorPane>