Skip to content
Advertisement

How to set order for dynamically added JavaFX components?

I have a button that generates another button each time it’s clicked. 1 of the problems is, that the generated button is placed in the wrong location. The buttons should start around the Top Left side of the window, but the location of the buttons is at the bottom left of the window. I can’t use the function setAlignment(Pos.TOP_LEFT) to change the location because the generated buttons are children of an AnchorPane object.

Nor can I use something like Scenebuilder, since the generated buttons only exist after a button has been clicked.

If I set the buttons to be children of a VBox object, and change the parameter in the function `vbox.getChildren().add(0, new Button( ” New Entry “+button1ClickCount )) to a 1 instead of 0, the buttons are created in an ascending order, starting at the top of the window, but all the children below the generated buttons get pushed below the screen + the first generated button doesn’t stay above newer generated buttons.

How do you set the location in Java for a Button or other component that doesn’t exist before runtime? And have them in an ascending order, instead of descending, without pushing out FXML components below the newly generated ones?

The button at the bottom of the window in the image should appear right below and to the left of the blue folder.

wrong location

My Main.Java class

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.*;

import javafx.stage.Screen;
import javafx.stage.Stage;

import java.net.URL;
import java.lang.*;

public class Main extends Application {

    @FXML
    public static VBox vbox = new VBox();
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        ButtonFXMLController controller = new ButtonFXMLController();

        FXMLLoader loader = new FXMLLoader();
        loader.setController(controller);

       String ProjectPath = System.getProperty("user.dir")+"/MyFXML.fxml";
       //Sets the value of a String to be the working directory path + the path of the file "MyFXML.fxml"

        loader.setLocation(new URL(   "file:///"+ProjectPath));
        vbox = loader.<VBox>load();
        Scene scene = new Scene(vbox);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

The Button FXML Controller Class

import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;

public class ButtonFXMLController {

    @FXML
    private int   button1ClickCount = 0;
// the ID of each generated buttons, starts with 0

    @FXML
    public void buttonClicked(Event e){

        System.out.println(8);
     
        AnchorPane anchorpane = new AnchorPane();
      Main.vbox.getChildren().add(anchorpane);

 anchorpane.getChildren().add(0, new Button( " New Entry "+button1ClickCount ));


        button1ClickCount++;

        String text = "Button1 clicked " +button1ClickCount + " times";

        System.out.println(text);

    }
}

My FXML file

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

<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>

<VBox prefHeight="871.0" prefWidth="1425.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
        <children>
          <AnchorPane maxHeight="-1.0" maxWidth="-1.0" VBox.vgrow="ALWAYS">
            <children>
                  <TextField layoutX="307.0" layoutY="59.0" opacity="0.59" prefHeight="31.0" prefWidth="1154.0" text="  Search..." />
                  <Button fx:id="TitelButton" layoutX="311.0" layoutY="174.0" mnemonicParsing="false" onAction="#buttonClicked" prefHeight="31.0" prefWidth="119.0" text="Titel" />
                  <TextField layoutX="311.0" layoutY="208.0" prefHeight="31.0" prefWidth="119.0" />

                  <Button fx:id="Entity" contentDisplay="GRAPHIC_ONLY" layoutX="68.0" layoutY="174.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="119.0" style="-fx-background-color: transparent;" text="General">
                      <graphic>
                          <ImageView fitHeight="49.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
                              <image>
                                  <Image url="@folder.png" />
                              </image>
                          </ImageView>
                      </graphic>
              </Button>
            <AnchorPane fx:id="anchorpane" layoutX="73.0" layoutY="232.0" prefHeight="200.0" prefWidth="200.0">
            </AnchorPane>
            </children>
          </AnchorPane>
        </children>
      </VBox>

Advertisement

Answer

You can use setLayoutX and setLayoutY in the ButtonFXMLController with a y incremented to ensure that the buttons will not created in the same place:

public class ButtonFXMLController {

@FXML
private int   button1ClickCount = 0;
private int   y = 250;
// the ID of each generated buttons, starts with 0

@FXML
public void buttonClicked(Event e){

    System.out.println(8);
  Button b = new Button(" New Entry "+button1ClickCount);
    // set the place here :
    b.setLayoutX(250);
    b.setLayoutY(y+=20);
    AnchorPane anchorpane = new AnchorPane();
  Main.vbox.getChildren().add(anchorpane);

  anchorpane.getChildren().add(0, b);

    Main.vbox.setAlignment(Pos.TOP_CENTER);

    button1ClickCount++;

    String text = "Button1 clicked " +button1ClickCount + " times";

    System.out.println(text);

}
}

Advertisement