In this tutorial you will learn about Layout via simple step by step examples.

Example 1: Create custom AutoResponsive Layout

An example of how to implement your own layout of controls contained inside a Pane. The JavaFX Pane class does not do any layout of its children. The Pane shows the children where the children wants to be layed out themselves. Thus, by changing layout position of the children of a Pane you can change it's layout.

Follow the following steps:

Step 1: Create Project

  1. Open your favorite Java IDE.
  2. In the menu go to File --> Create New Project.

Step 2: Add Dependencies

No dependencies are needed for this project.

Step 3: Write Code

Our code will comprise the following Java files:

  • AutoResponsiveLayout.java
  • AutoResponsiveLayoutExample.java
  1. In your editor or IDE, create a file known as AutoResponsiveLayout.java.
  2. Then add the following code:

(a). AutoResponsiveLayout.java

package com.jenkov.javafx.layout;

import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;

import java.util.ArrayList;
import java.util.List;

public class AutoResponsiveLayout {

    public static class WidgetLayoutInfo {

        public double x = 0.0D;
        public double y = 0.0D;

        public double minWidth  = 0.0D;
        public double width     = 0.0D;

        public double minHeight = 0.0D;
        public double height    = 0.0D;

        public int   rowNo = 0;
    }

    public static class RowLayoutInfo {
        public int    rowNo    = 0;
        public double rowWidth = 0.0D;

        public List<WidgetLayoutInfo> widgets = new ArrayList<>();
    }

    public static class PaneLayoutInfo {

        public List<WidgetLayoutInfo> widgetLayoutInfos = new ArrayList<>();
        public List<RowLayoutInfo>    rowLayoutInfos    = new ArrayList<>();

        public int    noOfRows    = 0;
        public double maxRowWidth = 0.0D;

        public double totalChildWidth = 0.0D; //width of all children if placed on a single row
        public double avgRowWidth     = 0.0D;  // total child width divided by number of rows.
        public double visibleHeight   = 0.0D; // The height visible within the parent ScrollPane

        public void initRows() {
            for(int i = this.rowLayoutInfos.size(); i <= noOfRows; i++) {
                RowLayoutInfo rowLayoutInfo = new RowLayoutInfo();
                rowLayoutInfo.rowNo = i;
                this.rowLayoutInfos.add(rowLayoutInfo);
            }
        }

        public void resetRows() {
            for(int i=0; i<this.rowLayoutInfos.size(); i++) {
                RowLayoutInfo rowLayoutInfo = this.rowLayoutInfos.get(i);
                rowLayoutInfo.widgets.clear();
            }
        }

        public void assignWidgetsToRows() {
            resetRows();
            for(int i=0; i<widgetLayoutInfos.size(); i++) {
                WidgetLayoutInfo widgetLayoutInfo = widgetLayoutInfos.get(i);
                RowLayoutInfo rowLayoutInfo = rowLayoutInfos.get(widgetLayoutInfo.rowNo);
                rowLayoutInfo.widgets.add(widgetLayoutInfo);
            }
        }

        public int determineRowCountFromWidgetLayoutInfos() {
            this.noOfRows = getLastWidgetLayoutInfo(this.widgetLayoutInfos).rowNo + 1; // row numbers are 0-based (first row has index 0)
            return this.noOfRows;
        }

        private WidgetLayoutInfo getLastWidgetLayoutInfo(List<WidgetLayoutInfo> widgetLayoutInfos) {
            return widgetLayoutInfos.get(widgetLayoutInfos.size()-1);
        }

        public void calculateTotalChildMinWidth(){
            this.totalChildWidth = 0.0D;
            for(int i=0; i<this.widgetLayoutInfos.size(); i++) {
                WidgetLayoutInfo widgetLayoutInfo = this.widgetLayoutInfos.get(i);
                double childWidth = widgetLayoutInfo.minWidth;
                this.totalChildWidth += childWidth;
            }
        }

        public void calculateAverageRowWidthBasedOnMinWidths() {
            this.avgRowWidth = this.totalChildWidth / this.noOfRows;
        }

        private double calcMinimumUsedRowHeights() {
            int rowEndIndex = 0;
            double minimumUsedRowHeights = 0.0D;
            for(int rowNo = 0; rowNo < this.noOfRows; rowNo++){
                double highestWidgetsOnRow = 0.0D;
                while(rowEndIndex < this.widgetLayoutInfos.size() && rowNo == this.widgetLayoutInfos.get(rowEndIndex).rowNo) {
                    WidgetLayoutInfo widgetLayoutInfo = this.widgetLayoutInfos.get(rowEndIndex);
                    highestWidgetsOnRow = Math.max(highestWidgetsOnRow, widgetLayoutInfo.minHeight);
                    rowEndIndex++;
                }
                minimumUsedRowHeights += highestWidgetsOnRow;
            }
            return minimumUsedRowHeights;
        }

    }

    // Feature flags. All features should be enabled for a fully automatic responsive layout

    protected boolean balanceRows       = true;
    protected boolean pullUpChildren    = true;
    protected boolean extendChildWidth  = true;
    protected boolean extendChildHeight = true;

    PaneLayoutInfo          paneLayoutInfo = new PaneLayoutInfo();

    private Pane targetPane = null;
    private ScrollPane targetParentPane = null;

    public AutoResponsiveLayout(Pane pane, ScrollPane parent) {
        this.targetPane = pane;
        this.targetParentPane = parent;

        this.targetPane.widthProperty().addListener((ObservableValue<? extends Number> property, Number oldValue, Number newValue) -> {
            this.paneLayoutInfo.maxRowWidth = newValue.doubleValue();
            layoutPane();
        });

        parent.viewportBoundsProperty().addListener((ObservableValue<? extends Bounds> property, Bounds oldValue, Bounds newValue) -> {
            this.paneLayoutInfo.visibleHeight = newValue.getHeight();
            layoutPane();
        });

    }

    public void clear() {
        //this.paneLayoutInfo.resetRows();
        this.paneLayoutInfo.widgetLayoutInfos.clear();
        this.targetPane.getChildren().clear();
    }

    public void addWidget(Region child) {
        WidgetLayoutInfo widgetLayoutInfo = new WidgetLayoutInfo();
        widgetLayoutInfo.x        = 0.0D;
        widgetLayoutInfo.y        = 0.0D;
        widgetLayoutInfo.rowNo    = 0;
        widgetLayoutInfo.minWidth = child.getMinWidth();
        widgetLayoutInfo.width    = child.getMinWidth(); //start with min width as width
        widgetLayoutInfo.minHeight= child.getMinHeight();
        widgetLayoutInfo.height   = child.getMinWidth();

        addWidget(child, widgetLayoutInfo);
    }

    public void addWidget(Region child, WidgetLayoutInfo layoutInfo) {
        this.targetPane.getChildren().add(child);
        this.paneLayoutInfo.widgetLayoutInfos.add(layoutInfo);

    }

    protected void layoutPane() {
        //System.out.println("============== BEGIN LAYOUT ===============");
        ObservableList<Node> children = this.targetPane.getChildren();
        if(children.size() == 0) {
            return;
        }

        transferMinWidthsAndHeightsToWidths();

        // Phase 1: Divide children into rows based on their minimum widths
        assignChildrenToRowNumbersAccordingToMinWidths();

        this.paneLayoutInfo.determineRowCountFromWidgetLayoutInfos();
        //this.paneLayoutInfo.initRows();
        //this.paneLayoutInfo.resetRows();
        //this.paneLayoutInfo.assignWidgetsToRows();

        adjustPaneToParentScrollPaneOrMinUsedRowsHeight();

        // Phase 2.1: Now that number of rows is decided, calculate the average width of rows
        paneLayoutInfo.calculateTotalChildMinWidth();
        paneLayoutInfo.calculateAverageRowWidthBasedOnMinWidths();

        // Phase 2.2: Assign children to rows based on average row width instead of max row width - for a more even distribution of children.
        if(this.balanceRows) {
            assignChildrenToRowsUsingAverageRowWidth();
        }

        // Phase 2.3 Pull up "dangling" widgets towards the top of the pane, so the grid looks more similar.
        if(this.pullUpChildren) {
            pullUpWidgets(children, this.paneLayoutInfo.widgetLayoutInfos);
        }

        // Phase 3: Expand widths of children to match row width
        if(this.extendChildWidth) {
            expandWidgetWidthsToFitRow(this.paneLayoutInfo.maxRowWidth, children);
        }

        // Phase 4: Expand heights of children to match highest child per row
        if(this.extendChildHeight) {
            expandRowHeights();
        }

        // Phase 5: Position children according to index and row
        positionAndSizeChildren(children, this.paneLayoutInfo.widgetLayoutInfos);

    }

    private int determineRowCountFromWidgetLayoutInfos() {
        return getLastWidgetLayoutInfo(this.paneLayoutInfo.widgetLayoutInfos).rowNo + 1; // row numbers are 0-based (first row has index 0)
    }

    private void adjustPaneToParentScrollPaneOrMinUsedRowsHeight() {
        double minimumUsedRowHeights = this.paneLayoutInfo.calcMinimumUsedRowHeights();
        double newHeight = Math.max(this.paneLayoutInfo.visibleHeight, minimumUsedRowHeights);
        this.targetPane.setMinHeight(newHeight);
        this.targetPane.setPrefHeight(newHeight);
        this.targetPane.setMaxHeight(newHeight);
    }

    private void transferMinWidthsAndHeightsToWidths() {
        for(int i=0; i<this.paneLayoutInfo.widgetLayoutInfos.size(); i++){
            WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(i);
            widgetLayoutInfo.width  = widgetLayoutInfo.minWidth;
            widgetLayoutInfo.height = widgetLayoutInfo.minHeight;
        }
    }

    private void pullUpWidgets(ObservableList<Node> children, List<WidgetLayoutInfo> widgetLayoutInfos) {
        int    childrenPulledUpThisIteration = 0;
        do{
            childrenPulledUpThisIteration = 0;
            //System.out.println("===== Pull up round =====");
            double prevRowWidth = Double.MAX_VALUE;
            double thisRowWidth = 0.0D;
            int    thisRowNo    = 0;

            //Node firstChildOnRow = children.get(0);
            WidgetLayoutInfo firstChildOnRowWidgetLayoutInfo = widgetLayoutInfos.get(0);
            for(int i = 0; i < children.size(); i++) {
                WidgetLayoutInfo widgetLayoutInfo = widgetLayoutInfos.get(i);
                if(thisRowNo == widgetLayoutInfo.rowNo) {
                    thisRowWidth += widgetLayoutInfo.minWidth;
                } else {
                    double rowDiff = thisRowWidth - prevRowWidth;
                    //if(rowDiff >= firstChildOnRow.getLayoutBounds().getWidth()) {
                    if(rowDiff >= firstChildOnRowWidgetLayoutInfo.minWidth) {
                        //System.out.println("Move child " + i + " up to previous row");
                        firstChildOnRowWidgetLayoutInfo.rowNo--; //move first widget of this row up to previous row
                        childrenPulledUpThisIteration++;
                    } else {
                        //System.out.println("Row diff for row " + thisRowNo);
                    }

                    //firstChildOnRow = child;
                    firstChildOnRowWidgetLayoutInfo = widgetLayoutInfo;
                    prevRowWidth = thisRowWidth;
                    //thisRowWidth = child.getLayoutBounds().getWidth();
                    thisRowWidth = widgetLayoutInfo.minWidth;
                    thisRowNo++;
                }
            }
        } while (childrenPulledUpThisIteration > 0);
    }

    private void expandWidgetWidthsToFitRow(double newWidth, ObservableList<Node> children) {
        double usedRowWidth = 0.0D;

        int rowStartIndex = 0;
        int rowEndIndex   = 0;
        for(int rowNo = 0; rowNo < paneLayoutInfo.noOfRows; rowNo++){

            while(rowEndIndex < this.paneLayoutInfo.widgetLayoutInfos.size() && rowNo == this.paneLayoutInfo.widgetLayoutInfos.get(rowEndIndex).rowNo){
                rowEndIndex++;
            }
            for(int i=rowStartIndex; i<rowEndIndex; i++) {
                //Node node = children.get(i);
                //usedRowWidth += node.getLayoutBounds().getWidth();
                WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(i);
                usedRowWidth += widgetLayoutInfo.minWidth;
            }

            //System.out.println("   Max Row Width : " + newWidth + "(" + paneLayoutInfo.maxRowWidth + ")");
            //System.out.println("   Used Row width: " + usedRowWidth);

            double unusedRowWidth = paneLayoutInfo.maxRowWidth - usedRowWidth;
            //System.out.println("   Unused row width: " + unusedRowWidth);

            for(int i=rowStartIndex; i<rowEndIndex; i++) {
                Node node = children.get(i);

                WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(i);
                double childWidth      = widgetLayoutInfo.minWidth;
                double childToRowRatio = childWidth / usedRowWidth;
                double childWidthExtension = unusedRowWidth * childToRowRatio;
                double childWidthExtended = childWidth + childWidthExtension;

                //System.out.println("      Child Width Extension: " + childWidthExtension);
                //System.out.println("      Child Width Extended : " + childWidthExtended);

                widgetLayoutInfo.width = childWidthExtended;
                //((Region) node).setMinWidth(childWidthExtended);
                //((Region) node).setPrefWidth(childWidthExtended);
            }

            usedRowWidth = 0.0D;
            rowStartIndex = rowEndIndex;
        }
    }

    private void expandRowHeights() {
        double minimumUsedRowHeights = this.paneLayoutInfo.calcMinimumUsedRowHeights();

        double unusedHeight = 0.0D;
        //if(this.paneLayoutInfo.visibleHeight > this.targetPane.getHeight()) {
        if(this.paneLayoutInfo.visibleHeight > minimumUsedRowHeights) {
            //unusedHeight = Math.max(0, this.targetPane.getHeight() - minimumUsedRowHeights);
            unusedHeight = Math.max(0, this.paneLayoutInfo.visibleHeight - minimumUsedRowHeights);
        }

        //if minimumUsedRowHeights is larger than available height - do NOT use a negative unusedHeight - but use 0.

        //System.out.println("Pane height        : " + this.targetPane.getHeight());
        //System.out.println("Visible height     : " + this.paneLayoutInfo.visibleHeight);
        //System.out.println("Minimum rows height: " + minimumUsedRowHeights);
        //System.out.println("Unused height      : " + unusedHeight);

        int rowStartIndex = 0;
        int rowEndIndex   = 0;
        for(int rowNo = 0; rowNo < paneLayoutInfo.noOfRows; rowNo++){
            rowStartIndex = rowEndIndex;
            double highestWidgetsOnRow = 0.0D;
            while(rowEndIndex < this.paneLayoutInfo.widgetLayoutInfos.size() && rowNo == this.paneLayoutInfo.widgetLayoutInfos.get(rowEndIndex).rowNo) {
                WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(rowEndIndex);
                highestWidgetsOnRow = Math.max(highestWidgetsOnRow, widgetLayoutInfo.height);
                rowEndIndex++;
            }
            double rowRatio       = highestWidgetsOnRow / minimumUsedRowHeights;
            double rowExtension   = rowRatio * unusedHeight;
            double expandedHeight = highestWidgetsOnRow + rowExtension;
            //System.out.println("Row Height     : " + highestWidgetsOnRow);
            //System.out.println("Unused height  : " + unusedHeight);
            //System.out.println("Expanded height: " + expandedHeight);

            rowEndIndex = rowStartIndex;
            while(rowEndIndex < this.paneLayoutInfo.widgetLayoutInfos.size() && rowNo == this.paneLayoutInfo.widgetLayoutInfos.get(rowEndIndex).rowNo) {
                WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(rowEndIndex);
                widgetLayoutInfo.height = expandedHeight;
                rowEndIndex++;
            }

        }
    }

    private void printWidgetRows(ObservableList<Node> children) {
        System.out.println("=== Widget Row Nos ===");
        for(int i = 0; i< children.size(); i++) {
            WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(i);
            System.out.println("Widget " + i + " has row " + widgetLayoutInfo.rowNo);
        }
    }

    private WidgetLayoutInfo getLastWidgetLayoutInfo(List<WidgetLayoutInfo> widgetLayoutInfos) {
        return widgetLayoutInfos.get(widgetLayoutInfos.size()-1);
    }

    private void assignChildrenToRowNumbersAccordingToMinWidths() {
        ObservableList<Node> children = targetPane.getChildren();
        double maxRowWidth = paneLayoutInfo.maxRowWidth;

        double widgetsOnRowWidth = 0.0D;
        int rowNo = 0;
        for(int i = 0; i < children.size(); i++) {
            WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(i);

            double childWidth =  widgetLayoutInfo.minWidth;
            widgetsOnRowWidth += childWidth;
            if(widgetsOnRowWidth > maxRowWidth && i>0) {
                rowNo++;
                widgetsOnRowWidth = childWidth;
            }
            widgetLayoutInfo.rowNo = rowNo;
        }
    }

    private void assignChildrenToRowsUsingAverageRowWidth() {
        //System.out.println("Avg. row width: " + avgRowWidth);
        double avgRowWidth = paneLayoutInfo.avgRowWidth;
        double maxRowWidth = paneLayoutInfo.maxRowWidth;
        double totalWidgetsWidthUsed = 0.0D;
        double widgetWidthOnRowUsed  = 0.0D;
        int rowNo = 0;
        for(int i = 0; i < this.paneLayoutInfo.widgetLayoutInfos.size(); i++) {
            WidgetLayoutInfo widgetLayoutInfo = this.paneLayoutInfo.widgetLayoutInfos.get(i);
            double childWidth = widgetLayoutInfo.minWidth;

            widgetWidthOnRowUsed  += childWidth;
            totalWidgetsWidthUsed += childWidth;

            double avgRowWidthSum = avgRowWidth * ((double) (rowNo + 1) );

            if(widgetWidthOnRowUsed > maxRowWidth){
                // widget cannot fit within this row - push to next row.
                widgetWidthOnRowUsed = childWidth;
                rowNo++;
                widgetLayoutInfo.rowNo = rowNo;
            }
            if(totalWidgetsWidthUsed >= avgRowWidthSum) {
                // widget can fit within this row - but after this widget break to next row
                widgetLayoutInfo.rowNo = rowNo;
                rowNo++;
                widgetWidthOnRowUsed = 0.0D;
            } else {
                widgetLayoutInfo.rowNo = rowNo;
            }
        }
    }

    private void positionAndSizeChildren(ObservableList<Node> children, List<WidgetLayoutInfo> widgetLayoutInfos) {
        int rowNo = 0;
        double x = 0.0D;
        double y = 0.0D;
        for(int i = 0; i< children.size(); i++) {
            Region           child            = (Region) children.get(i);
            WidgetLayoutInfo widgetLayoutInfo = widgetLayoutInfos.get(i);

            if(rowNo != widgetLayoutInfo.rowNo) {

                double highestWidgetOnRow = 0.0D;
                System.out.print("Calculating height for row: " + rowNo);
                for(int j=i-1; j>=0; j--) {
                    WidgetLayoutInfo widgetOnRow = widgetLayoutInfos.get(j);
                    if(widgetOnRow.rowNo != rowNo) { //reached previous row - skip loop now.
                        break;
                    }
                    //highestWidgetOnRow = Math.max(highestWidgetOnRow, widgetOnRow.minHeight);
                    highestWidgetOnRow = Math.max(highestWidgetOnRow, widgetOnRow.height);
                }
                System.out.println(" => " + highestWidgetOnRow);

                rowNo = widgetLayoutInfo.rowNo;
                x = 0.0D;

                y += highestWidgetOnRow;
            }

            child.setLayoutX(x);
            child.setLayoutY(y);
            child.setPrefWidth(widgetLayoutInfo.width);
            child.setPrefHeight(widgetLayoutInfo.height);

            x += widgetLayoutInfo.width;
        }
    }

}
  1. Next create another file known as AutoResponsiveLayoutExample.java.
  2. And add the following code:

(b). AutoResponsiveLayoutExample.java

package com.jenkov.javafx.layout;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.shape.StrokeType;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;

import java.util.List;

public class AutoResponsiveLayoutExample extends Application {

    private int widgetCount = 0;

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

    public void start(Stage primaryStage) {
        ScrollPane scrollPane = new ScrollPane();

        scrollPane.pannableProperty().set(true);
        scrollPane.fitToWidthProperty().set(true);
        //scrollPane.fitToHeightProperty().set(true);

        //scrollPane.setPrefHeight(1024);
        scrollPane.setPrefHeight(4096);

        scrollPane.hbarPolicyProperty().setValue(ScrollPane.ScrollBarPolicy.AS_NEEDED);
        scrollPane.vbarPolicyProperty().setValue(ScrollPane.ScrollBarPolicy.AS_NEEDED);

        Pane containerPane = new Pane();
        scrollPane.setContent(containerPane);
        AutoResponsiveLayout autoResponsiveLayout = new AutoResponsiveLayout(containerPane, scrollPane);

        ToolBar toolbar = createToolBar(containerPane, autoResponsiveLayout);

        //VBox vBox = new VBox(toolbar, containerPane);
        VBox vBox = new VBox(toolbar, scrollPane);
        Scene scene = new Scene(vBox);
        primaryStage.setScene(scene);

        primaryStage.setWidth(1024);
        primaryStage.setHeight(800);
        primaryStage.setTitle("Auto-responsive Layout Example");

        primaryStage.show();
    }

    private ToolBar createToolBar(Pane containerPane, AutoResponsiveLayout autoResponsiveLayout) {
        ToolBar toolbar = new ToolBar();

        addButton(autoResponsiveLayout, toolbar, "1x1", 256, 256);
        addButton(autoResponsiveLayout, toolbar, "2x1", 512, 256);
        addButton(autoResponsiveLayout, toolbar, "1x2", 256, 512);
        addButton(autoResponsiveLayout, toolbar, "2x2", 512, 512);

        toolbar.getItems().add(new Separator());

        ToggleButton toggleButton2 = new ToggleButton("Balance Rows");
        toggleButton2.setOnAction((event) -> {
            autoResponsiveLayout.balanceRows = !autoResponsiveLayout.balanceRows;
            autoResponsiveLayout.layoutPane();
        });

        toolbar.getItems().add(toggleButton2);

        ToggleButton toggleButton1 = new ToggleButton("Pull Up Children");
        toggleButton1.setOnAction((event) -> {
            autoResponsiveLayout.pullUpChildren = !autoResponsiveLayout.pullUpChildren;
            autoResponsiveLayout.layoutPane();
        });

        toolbar.getItems().add(toggleButton1);

        ToggleButton toggleButton3 = new ToggleButton("Expand Child Width");
        toggleButton3.setOnAction((event) -> {
            autoResponsiveLayout.extendChildWidth = !autoResponsiveLayout.extendChildWidth;
            autoResponsiveLayout.layoutPane();
        });

        toolbar.getItems().add(toggleButton3);

        ToggleButton toggleButton4 = new ToggleButton("Expand Child Height");
        toggleButton4.setOnAction((event) -> {
            autoResponsiveLayout.extendChildHeight = !autoResponsiveLayout.extendChildHeight;
            autoResponsiveLayout.layoutPane();
        });

        toolbar.getItems().add(toggleButton4);

        toolbar.getItems().add(new Separator());

        ToggleButton toggleButton5 = new ToggleButton("Clear");
        toggleButton5.setOnAction((event) -> {
            autoResponsiveLayout.clear();
            autoResponsiveLayout.layoutPane();
        });
        toolbar.getItems().add(toggleButton5);

        return toolbar;
    }

    private void addButton(AutoResponsiveLayout autoResponsiveLayout, ToolBar toolbar, String buttonText, double minWidth, double minHeight) {
        Button buttonAdd = new Button(buttonText);

        buttonAdd.setOnAction((event) -> {
            Pane widgetPane = createWidgetPane(minWidth, minHeight);
            autoResponsiveLayout.addWidget(widgetPane);
            autoResponsiveLayout.layoutPane();
        });

        toolbar.getItems().add(buttonAdd);
    }

    private Pane createWidgetPane(double minWidth, double minHeight) {
        this.widgetCount++;

        Pane widgetPane = new Pane();
        widgetPane.setMinWidth(minWidth);
        widgetPane.setMinHeight(minHeight);

        StrokeType     strokeType     = StrokeType.INSIDE;
        StrokeLineJoin strokeLineJoin = StrokeLineJoin.MITER;
        StrokeLineCap  strokeLineCap  = StrokeLineCap.BUTT;
        double         miterLimit     = 10;
        double         dashOffset     = 0;
        List<Double> dashArray      = null;

        BorderStrokeStyle borderStrokeStyle =
                new BorderStrokeStyle(
                        strokeType,
                        strokeLineJoin,
                        strokeLineCap,
                        miterLimit,
                        dashOffset,
                        dashArray
                );

        BorderStroke borderStroke =
                new BorderStroke(
                        //Color.valueOf("08ff80"),
                        Color.valueOf("#303F9F"),
                        borderStrokeStyle,
                        new CornerRadii(0),
                        new BorderWidths(8)
                );

        Border border = new Border(borderStroke);

        Label label = new Label("" + this.widgetCount);
        label.setFont(Font.font("Arial", FontWeight.BOLD , FontPosture.REGULAR, 32));
        label.setLayoutX(20);
        label.setLayoutY(20);
        widgetPane.getChildren().add(label);
        widgetPane.setBorder(border);
        return widgetPane;
    }
}

Step 4: Run

Copy the above code, add static main method and from it instantiate the above class and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author
3. Code: Apache 2.0 License