Home > Software design >  How to get a child node/pane from the stage? Javafx
How to get a child node/pane from the stage? Javafx

Time:08-15

I need to get to my stackpane that is nested inside a borberpane which is also nested in another borderpane(root).

I did not create this by code, I used scene-builder/FXML.

I am now trying to access it through code. The closes I got was by using a parent and got a unmodifiable list which seems to only have its two child but I cant seem to go deeper.

Here is the Hierarchy---

<BorderPane fx:id="rootPane" focusTraversable="true" minHeight="0.0" minWidth="0.0" prefHeight="771.0" prefWidth="1100.0" stylesheets="@styling.css" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.passwordmanager2.HelloController">
   <center>
      <BorderPane fx:id="borderPane2" BorderPane.alignment="CENTER">
         <top>
            <StackPane fx:id="topBar" alignment="TOP_CENTER" focusTraversable="true" prefHeight="95.0" BorderPane.alignment="CENTER">
               <children>
                  .....

Here is main method

public class HelloApplication extends Application {


    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
        double width = 900.0;
        double height = 950.0;

        Scene scene = new Scene(fxmlLoader.load(), width, height);
        Parent root = fxmlLoader.getRoot();
        System.out.println(root.getChildrenUnmodifiable().get(3)); // trying to get stackPane

        stage.setScene(scene);
        stage.initStyle(StageStyle.UNDECORATED);

        ResizeHelper.addResizeListener(stage);

        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}

CodePudding user response:

You have to create fields named the same way you specified in the .fxml file (with fx:id="..."), for each component and use the @FXML annotation.

For example you have to add @FXML private BorderPane borderPane2; to access the border pane object.

The best way to implement that is using the MVC design pattern. References:

  • enter image description here

    Project structure:

    src
     |
      - application (package)
          |
           -- Controller.java
          |
           -- Main.java
          |
           -- Test.fxml
          |
           -- application.css
    

    Main.java class:

    package application;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.layout.AnchorPane;
    import javafx.stage.Stage;
    
    public class Main extends Application {
        @Override
        public void start(Stage stage) {
            
            try {
                FXMLLoader loader = new FXMLLoader(Main.class.getResource("Test.fxml"));
                AnchorPane basePane = (AnchorPane) loader.load();
                Scene scene = new Scene(basePane);
                scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
                stage.setTitle("Test");
                stage.setScene(scene);
                stage.show();
                
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        public static void main(String args[]) {
            launch(args);
        }
    }
    

    Controller.java class:

    package application;
    
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.scene.control.Slider;
    import javafx.scene.control.TextField;
    import javafx.scene.control.Button;
    import javafx.scene.layout.AnchorPane;
    
    public class Controller {
        @FXML
        private AnchorPane base;
        @FXML private Slider sliderTest;
        @FXML private TextField textFieldTest;
        @FXML private Button buttonTest;
        
        private int counter = 0;
    
        public void initialize()
        {
            textFieldTest.setText(""   counter);
        }
        
        @FXML private void test(ActionEvent event)
        {
            counter  ;
            this.textFieldTest.setText(""   counter);
        }
    }
    

    Test.fxml file:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.Slider?>
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.layout.AnchorPane?>
    
    <AnchorPane id="base" fx:id="base" prefHeight="400.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
       <children>
          <TextField fx:id="textFieldTest" layoutX="125.0" layoutY="187.0" />
          <Button fx:id="buttonTest" layoutX="174.0" layoutY="273.0" mnemonicParsing="false" onAction="#test" text="Increment" />
          <Slider fx:id="sliderTest" layoutX="14.0" layoutY="33.0" />
       </children>
    </AnchorPane>
    

    application.css file:

    .slider {
        -fx-base: red;
    }
    .button {
        -fx-base: blue;
    }
    

    Another way to access a component (for example if it doesn't have a fx:id), you could start from the parent and, knowing the child node index, or iterating through them, you could get the interested node and cast it.
    Example:

    Node n = base.getChildren().get(0);
    TextField tf = (TextField) n;
    System.out.println(tf);
    tf.setText("Hello JavaFX");
    

    Output:

    TextField[id=textFieldTest, styleClass=text-input text-field]
    

    here the TextField is the 1st child of AnchorPane:

    enter image description here

  • Related