Introduction to JavaFx and working with layout in examples

    Good day. In this article, I will describe the basics of working with the classes of the javafx.scene.layout. * Package (BorderPane, AnchorPane, StackPane, GridPane, FlowPane, TilePane, HBox, VBox) and their features in step-by-step examples and illustrations. Also, briefly go over the JavaFx class hierarchy.



    After installing Eclipse and the e (fx) lipse plugin, create a new project:



    Select a JavaFx project:



    Set up the project:



    By default, Eclipse will create the following:

    package application;
    import javafx.application.Application;
    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.layout.BorderPane;
    public class Main extends Application {
    	@Override
    	public void start(Stage primaryStage) {
    		try {
    			BorderPane root = new BorderPane();
    			Scene scene = new Scene(root,400,400);
    			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
    			primaryStage.setScene(scene);
    			primaryStage.show();
    		} catch(Exception e) {
    			e.printStackTrace();
    		}
    	}
    	public static void main(String[] args) {
    		launch(args);
    	}
    }
    


    A root node is added to the scene, it must be a class inherited from Parent (a node that can have children), the root node is added to the scene (a special container for the entire content of the node graph), and it, in turn, to the stage, which is displayed.

    Let's take a look at the JavaFx class hierarchy:



    The most basic abstract class is Node - a node in the scene graph, fields are provided for the heirs to adjust the sizes: (minWidth - minimum width, minHeight - minimum height, prefWidth - preferred width, prefHeight - preferred height, maxWidth - maximum width, maxHeight - maximum height).

    Node coordinates: getLayoutX () and getLayoutY ()
    relocate (double x, double y)- changes the coordinates of the node, if you need to adjust the position of each coordinate separately, use setLayoutX (double value) and setLayoutY (double value)

    It is important to understand that the coordinates and dimensions set (pref, i.e. prefer - preferably) during layout, depending on the graph hierarchy nodes and their settings may differ from expected. I will give examples a bit later.

    Node cannot contain children; this is logical, for this there is a Parent direct descendant of Node, into which you can add and remove children. By the way, there are classes that represent nodes, but do not contain child nodes: Camera, Canvas, ImageView, LightBase, MediaView, Parent, Shape, Shape3D, SubScene, SwingNode.

    Today we are interested in the subgroup of the heirs of the Region class (the base class of all layuat containers), in particular, we will talk about the main descendants of the Pane class about the panels that are most often required in everyday development.

    Borderpan


    This is a special panel that has its children nodes top (setTop (Node)), bottom (setBottom (Note)), left (setLeft (Node)), right (setRight (Node)) and central (setCenter (Node)) positions, add several buttons to all these positions on the BotderPane:

    BorderPane root = new BorderPane();
    root.setLeft(new Button("Left"));
    root.setTop(new Button("Top"));
    root.setRight(new Button("Right"));
    root.setBottom(new Button("Bottom"));
    root.setCenter(new Button("Center"));
    

    The top and bottom sections have priority, so they narrow down the rest in height:



    When trying to set coordinates, for example, at the top button:

    BorderPane root = new BorderPane();
    root.setLeft(new Button("Left"));
    Button topButton = new Button("Top"); 
    topButton.setLayoutX(20.0);
    topButton.setLayoutY(20.0);
    root.setTop(topButton);
    root.setRight(new Button("Right"));
    root.setBottom(new Button("Bottom"));
    root.setCenter(new Button("Center"));
    

    The button will not change its position, why is this happening? When arranging children in the layoutChildren method of the BorderPane class, the position of each node is redefined, taking into account all the settings. There are several solutions to fix, for example, place (wrap) a button in an additional suitable container, for example, in the base for all panels

    Pane


    BorderPane root = new BorderPane();
    root.setLeft(new Button("Left"));
    //
    Pane pane = new Pane();
    Button topButton = new Button("Top");
    topButton.setLayoutX(20.0);
    topButton.setLayoutY(20.0);
    pane.getChildren().add(topButton);
    root.setTop(pane);
    //
    root.setRight(new Button("Right"));
    root.setBottom(new Button("Bottom"));
    root.setCenter(new Button("Center"));
    

    Because Pane does not redefine the position of its children, we get the desired offset:



    You can not wrap the button, but simply set it to indent using the static method setMargin (Node child, Insets value) :

    BorderPane.setMargin(topButton, new Insets(20.0));
    

    Insets is a helper class for setting indents, the constructor is overloaded, it can take one argument for all sides, and for each side separately, while we set up one indent for all sides, this is what we got:



    Remove the indents from the bottom and to the right and get desired button offset:

    BorderPane.setMargin(topButton, new Insets(20.0, 0.0, 0.0, 20.0));
    


    Stackpan


    Now let's look at a situation in which the panel imposes on children not only a position, but also tries to stretch them across the entire width and height, filling the entire content area, replace BorderPane and add TextArea and Button there first.

    StackPane root = new StackPane();
    root.getChildren().add(new TextArea("TextArea in StackPane"));
    root.getChildren().add(new Button("Button in StackPane"));
    Scene scene = new Scene(root,250,250);
    

    By the way, to add multiple nodes in the desired order, you can use the method:

    root.getChildren().addAll(Node1, Node2, ....);
    

    What we see, the text field stretched across our panel, and the button was centered:



    Centering can be adjusted using setAlignment (Pos)

    root.setAlignment(Pos.BOTTOM_RIGHT);
    

    Indent with setPadding (Insets)

    root.setPadding(new Insets(10.0));
    




    You can customize the centering and indentation of each node using static methods:

    StackPane root = new StackPane();
    TextArea textArea = new TextArea("TextArea in StackPane");
    StackPane.setMargin(textArea, new Insets(10.0, 0.0, 30.0, 50.0));
    Button button = new Button("Button in StackPane");
    StackPane.setAlignment(button, Pos.CENTER_RIGHT);
    root.getChildren().addAll(textArea, button);
    


    Result:



    Anchorpan


    The anchor panel allows you to snap the edges of child nodes with offsets to the edges of the panel, consider an example:

    Add a button and snap it to the right edge: Add a snap to the bottom edge:

    AnchorPane root = new AnchorPane();
    Button button = new Button("Button in AnchorPane");
    root.getChildren().add(button);
    AnchorPane.setRightAnchor(button, 10.0);





    AnchorPane.setBottomAnchor(button, 10.0);
    




    Now in the left edge and top:

    AnchorPane.setRightAnchor(button, 10.0);
    AnchorPane.setTopAnchor(button, 10.0);
    

    We get that the edges of the button are now rigidly attached to the edges of the panel, if you start to drag the window, the button will also stretch.



    Gridpan


    Consider a very useful grid panel, adding children to this panel must be done through the add method (Node child, int columnIndex, int rowIndex) in which the first parameter is added to the node, the second column number, the third row number, here is a simple example:

    GridPane root = new GridPane();
    // Для отображения сетки
    root.setGridLinesVisible(true);
    root.add(new Label("0x0"), 0, 0);
    root.add(new Label("0x1"), 0, 1);
    root.add(new Label("1x1"), 1, 1);
    root.add(new Label("1x2"), 1, 2);
    root.add(new Label("5x5"), 5, 5);
    

    We see that nodes can be added to any cell, empty columns and rows are created automatically:



    To work with columns, there is a special class ColumnConstraints , for this you need to create columns, configure them and add them to the GridPane, for example, if we want to set the width of the first columns 130, and the second 20%:

    GridPane root = new GridPane();
    root.setGridLinesVisible(true);
    root.add(new Label("0x0"), 0, 0);
    root.add(new Label("0x1"), 0, 1);
    root.add(new Label("1x1"), 1, 1);
    root.add(new Label("1x2"), 1, 2);
    root.add(new Label("5x5"), 5, 5);
    //
    ColumnConstraints columnConstraints = new ColumnConstraints();
    columnConstraints.setPrefWidth(130.0);
    ColumnConstraints columnConstraints1 = new ColumnConstraints();
    columnConstraints1.setPercentWidth(20);
    root.getColumnConstraints().addAll(columnConstraints, columnConstraints1);
    //
    

    We get:



    These are the most basic features, you will need to write a separate article to cover all the intricacies of GridPane settings.

    Flowpan


    Let's immediately, for example, from it everything will immediately become clear, we will add six buttons to FlowPane:

    FlowPane root = new FlowPane();
    root.getChildren().add(new Button("Button #1"));
    root.getChildren().add(new Button("Button #2"));
    root.getChildren().add(new Button("Button #3"));
    root.getChildren().add(new Button("Button #4"));
    root.getChildren().add(new Button("Button #5"));
    root.getChildren().add(new Button("Button #6"));
    

    Let's see the result, the button is displayed one after the other (by default, FlowPane has horizontal output Orientation.HORIZONTAL)


    Now, when the window is reduced in width, we see that the child nodes begin to be transferred:


    And accordingly, if you set the vertical orientation

    root.setOrientation(Orientation.VERTICAL);
    



    When reducing the height of the window we get a transfer:



    Vertical and horizontal indentation between elements can be adjusted using:

    root.setVgap(8);
    root.setHgap(4);
    

    TilePane The
    operation of this panel is similar to the operation of FlowPane, the difference is that the child nodes are placed in a grid of a cell of the same size, we give the previous example, but this time let one button be larger than the rest:


    As we can see, all the nodes are now in " tile "of the same size, stretched over the largest node.

    HBox and VBox


    These are the usual horizontal and vertical lists, combine them to achieve the desired result:

    VBox root = new VBox();
    HBox hBox = new HBox();
    hBox.getChildren().addAll(new Button("Button#1"), new Button("Button#2"));
    Slider slider = new Slider(1.0, 10.0, 4.0);
    slider.setShowTickLabels(true);
    root.getChildren().add(new Label("Label"));
    root.getChildren().addAll(hBox, slider);
    



    These are all descendants of the Pane class, thanks for watching.

    Also popular now: