board

Monday, June 25, 2012

JavaFX 2.0 Layout Panes - AnchorPane

An AnchorPane is similar to a BorderPane (see my previous post JavaFX 2.0 Layout Panes - BorderPane) as it also provides several areas or regions for your nodes.

In contrast to a BorderPane, an AnchorPane provides only four different regions: Left, Right, Bottom and Top (a BorderPane additionally provides a center region).

There are several more major differences between the two panes:

  • In an AnchorPane you can anchor multiple nodes to one area (in a BorderPane you can only set one node to each area).
  • In an AnchorPane you can anchor one single node to multiple areas, i.e. anchoring a Button to the left and the top of the AnchorPane, whereas in a BorderPane every node can only be applied to one area.
  • In an AnchorPane you can specify the offset to the anchor.
  • A BorderPane provides instance methods to populate each area (i.e. setCenter(Node node), setRight(Node node), ...). An AnchorPane offers static methods like AnchorPane.setTopAnchor(Node node, Double offset) that are applied directly to a Node.
  • In a BorderPane each child will grow and shrink with its parent depending on the area it is applied to. In an AnchorPane children will only be resized/stretched if they are anchored to opposite sides of the pane. For example if a Button is anchored to the left and the right anchor of an AnchorPane, the Button will be stretched horizontally.


Please take a look at this first simple example:


AnchorPane – Example 1

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 * Created on: 16.06.2012
 * @author Sebastian Damm
 */
public class AnchorPaneExample extends Application
{
    private final String LABEL_STYLE = "-fx-font: 20pt Cambria; "
            + "-fx-text-fill: white; "
            + "-fx-effect: dropshadow(one-pass-box, black, 10, 0, 3, 3);";
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        AnchorPane root = new AnchorPane();
        Scene scene = new Scene(root, 400, 200, Color.ROYALBLUE);
        
        Label lb1 = new Label("Top Anchor");
        lb1.setStyle(LABEL_STYLE);
        AnchorPane.setTopAnchor(lb1, 10d);
        AnchorPane.setLeftAnchor(lb1, 150d);
        
        Label lb2 = new Label("Right Anchor");
        lb2.setStyle(LABEL_STYLE);
        AnchorPane.setRightAnchor(lb2, 10d);
        AnchorPane.setTopAnchor(lb2, 85d);
        
        Label lb3 = new Label("Bottom Anchor");
        lb3.setStyle(LABEL_STYLE);
        AnchorPane.setBottomAnchor(lb3, 10d);
        AnchorPane.setLeftAnchor(lb3, 138d);
                
        Label lb4 = new Label("Left Anchor");
        lb4.setStyle(LABEL_STYLE);
        AnchorPane.setLeftAnchor(lb4, 10d);
        AnchorPane.setTopAnchor(lb4, 85d);
        
        root.getChildren().addAll(lb1, lb2, lb3, lb4);
        primaryStage.setTitle("AnchorPaneExample 1");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args)
    {   Application.launch(args);   }
}


For this first example we just create some Labels, apply some custom style (a dedicated post about css styling in an external css file will be posted once the series about layout panes is done) and anchor them at two anchors. The last step is to add all labels to the collection of childrens of the AnchorPane. Otherwise, the applied anchors won´t have any effect.

Your application should look like this now:

If you resize your window, it should look like one of the following two pictures:


You can see, that all labels maintain their position based on the anchors, they were applied to and the given offset.



In the next small example you will see the 'stretching' of the child nodes i mentioned at the beginning of this blog post:


AnchorPane – Example 2: Stretching child nodes

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 * Created on: 16.06.2012
 * @author Sebastian Damm
 */
public class AnchorPaneExample2 extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        AnchorPane root = new AnchorPane();
        Scene scene = new Scene(root, 400, 200, Color.ROYALBLUE);
        
        Button b1 = new Button("Button 1");
        AnchorPane.setTopAnchor(b1, 10d);
        AnchorPane.setLeftAnchor(b1, 20d);
        AnchorPane.setRightAnchor(b1, 20d);
        
        Button b2 = new Button("Button 2");
        AnchorPane.setTopAnchor(b2, 50d);
        AnchorPane.setBottomAnchor(b2, 20d);
        AnchorPane.setLeftAnchor(b2, 170d);
        
        root.getChildren().addAll(b1, b2);
        primaryStage.setTitle("AnchorPaneExample 2 - Stretching child nodes");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args)
    {   Application.launch(args);   }
}

This example contains two buttons, that are anchored to opposite sides of the AnchorPane(the third anchor is only applied to prevent an overlay of the two buttons). In order to keep the specified offset, the AnchorPane will stretch the Node, as long as it is a resizable Node. In the case of a non-resizable Node, only the top and the left anchor will be considered.

This code should result in something like this:



By resizing the window, the buttons should be stretched like in the following two screenshots:

So, these are the basics of the AnchorPane. Generally, i like a BorderPane more, but i think thats also up to personal preferences, because you can create the same layout in both panes. But in my experience, most layouts could be realized faster and with less code in a BorderPane.



1 comment: