Tobs
Tobs

Reputation: 29

JavaFX custom control use method

I made a custom control CustomControl in JavaFX.

The CustomControl is basically just a button and a text field. It is made of a CustomControl.fxml and a controller CustomControl.java.

I also have a view TestView.fxml which includes the CustomControl with a controller TestController.java. The TestView.fxml has a button. When that button is pressed it calls the method 'OnButtonPress' from the TestController.java. Now in that method I would like to call the method setText from the controller CustomControl.java.

Now I'm facing two problems. First: I'm getting the exception 'Root hasn't been set. Use method setRoot() before load.'

Second: I don't know how to call the method setText from my custom control.

Here's the code:

TestView.fxml:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane fx:controller="controller.TestController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <fx:include source="../custom_control.fxml" fx:id="custom_control"/>
      <Button onAction="#OnButtonPress" fx:id="button" layoutX="148.0" layoutY="117.0" mnemonicParsing="false" text="Button" />
    </children>
</AnchorPane>

TestController.java:

package controller;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;

public class TestController {

    @FXML
    private Button button;

    @FXML
    private VBox custom_control;

    public TestController() {
    }

    @FXML
    private void OnButtonPress() {
        // that is the method I would like to call
        custom_control.setText("This is the new text");
    }
}

CustomControl.java:

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

public class CustomControl extends VBox {
    @FXML private TextField textField;

    public CustomControl() {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        
        try {
            fxmlLoader.load();            
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    public void setText(String text){
        textField.textProperty().set(text);
    }
        
    @FXML
    protected void doSomething() {
        textField.textProperty().set("The button was clicked");
    }
}

CustomControl.fxml:

<?xml version="1.0" encoding="UTF-8"?> 
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml"> 
    <TextField fx:id="textField"/>
    <Button text="Click Me" onAction="#doSomething"/>
</fx:root>

Upvotes: 0

Views: 208

Answers (1)

Tobs
Tobs

Reputation: 29

Okey so I figured out why I didn't work so I though I'd share what problems I had.

  1. the name's of the packages have to start with a lower case letter not upper case
  2. The names of the Classes as well as the views (FXML files) have to start with a upper case letter.
  3. instead of <fx:include> you should use the actual tag of the control (in my case <CustomControl>) and import the FXML file

When doing all that it finally worked.

Upvotes: 2

Related Questions