Building GUI Applications With JavaFX

Lesson 6: Laying Out GUI Elements

By Alla Redko  
 
Version: JavaFX 1.3 « Previous 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Next »
 
The layout mechanism in the JavaFX SDK enables you to easily arrange and align components without specifying absolute coordinates for each UI object. Although absolute coordinates provide a certain flexibility, you might occasionally find the layout mechanism more convenient. The example code provided in this tutorial uses data binding and the declarative syntax of the JavaFX Script programming language. Refer to Learning the JavaFX Script Programming Language for more details on these concepts.
 

The example introduced in this lesson demonstrates how to arrange geometric shapes and standard UI components available through the JavaFX API.

Contents
Creating an Application Window
Defining Radio Buttons
Creating Circles
Applying the HBox Layout
Applying the VBox Layout
Using the Tile Layout
 

Consider creating three circles and a toggle group of radio buttons. Each radio button controls a color in the corresponding circle. When the radio button is selected the color is applied, otherwise the circle is gray. This scenario simulates a traffic light and is the example used in this tutorial to describe the layout mechanism.

Traffic Lights: Stop
Figure 1: Stop Light
Traffic Lights: Ready
Figure 2: Ready Light
Traffic Lights: Go
Figure 3: Go Light
 
Creating an Application Window

To create a window:

  1. Add an import statement for the Stage and Scene classes.

  2. Add the Stage object literal.

  3. Specify the title of the window.

  4. Add the Scene object literal to the scene instance variable of the Stage class.

  5. Set the width and the height of the scene.
import javafx.stage.Stage;
import javafx.scene.Scene;

Stage {
    title: "Traffic lights"
    scene: Scene{
	    width: 210
        height: 90
	}//Scene
}//Stage		
 
Defining Radio Buttons

Create a group of radio buttons in which only one button can be selected at a given time. This is called a toggle group. To define radio buttons:

  1. Add import statements for the ToggleGroup and RadioButton classes.

  2. Define the toggle group by using the ToggleGroup class.

    Note: In the example code for this lesson, you define a variable name for each UI element so that you can easily learn how the layout mechanism works. You also apply binding to the UI elements by referring to the variable names.

  3. Define the choiceText sequence for the button captions.

  4. Create a sequence of radio buttons within a cycle construction. The buttons enable selection of the particular traffic light by using the RadioButton class.

  5. Add each radio button to the group by using the toggleGroup instance variable.

The following code fragment defines a toggle group, then creates radio buttons that add them to the group.

import javafx.scene.control.ToggleGroup;
import javafx.scene.control.RadioButton;

def group = ToggleGroup{};
def choiceText = ["STOP", "READY", "GO"];

def choices = for (text in choiceText)
RadioButton{
        toggleGroup: group
        text: text
}//RadioButton
 
Creating Circles

To draw circles that indicate the traffic lights:

  1. Add import statements for the Circle, Color, RadialGradient, and Stop classes.

  2. Define the colors sequence for the colors of the circles.

  3. Create a sequence of circles within a cycle construction.

  4. Apply radial gradient fill to visually enhance the example.

    import javafx.scene.control.RadioButton;
    import javafx.scene.control.ToggleGroup;
    import javafx.scene.shape.Circle;
    import javafx.scene.paint.Color;
    import javafx.scene.paint.RadialGradient;
    import javafx.scene.paint.Stop;
    
    def group = ToggleGroup{};
    def choiceText = ["STOP", "READY", "GO"];
    
    def choices = for (text in choiceText)
    RadioButton{
            toggleGroup: group
            text: text
    }//RadioButton
    
    var colors = ["RED", "GOLD", "GREEN"];
    var lights = for (color in colors)
     Circle {
         centerX: 12
         centerY: 12
         radius: 12
         stroke: Color.GRAY
         fill: bind RadialGradient {
    	     centerX: 8,
                 centerY: 8,
                 radius: 12,
                 proportional: false
                 stops: [
                        Stop {offset: 0.0 color: Color.WHITE},
                        Stop {offset: 1.0 color:
                                     if (choices[indexof color].selected)
                                            then Color.web(color)
                                            else Color.GRAY
                        }//Stop
                 ]
          }//RadialGradient
     }//Circle
     
    The preceding code sample uses the data binding mechanism to change the color of the circle. If the selected instance variable of choices[1] is true, the color instance variable becomes Color.RED, otherwise it is Color.GRAY. Refer to Creating Graphical Objects for more information about shapes and visual effects.
Applying the HBox Layout

After all the components are created, you can use layout containers to arrange elements within the scene. This lesson explores the JavaFX Container: HBox, VBox, and Tile. In this example, you need a VBox object to lay out the radio buttons, an HBox object for the circles, and another HBox to arrange those two boxes.

A combination of HBox and VBox

Figure 4: Combination of HBox and VBox
 

To lay out the circles horizontally:

  1. Add an import statement for the HBox class.

  2. Arrange the circles within the horizontal box.

  3. Specify the spacing variable to set an offset between the circles.

  4. Set the nodeVPos instance variable to VPos.CENTER in this container so that circles will be centered vertically.
    The nodeVPos variable defines the vertical position of each node within the HBox container. Its default value is VPos.TOP.

  5. Remember to add an import statement for the VPos class.
  6.    HBox{ spacing: 15 content: lights nodeVPos: VPos.CENTER}
    
     
Applying the VBox Layout

To arrange the radio buttons:

  1. Add an import statement for the VBox class.

  2. Add the radio button sequence to the container's content.

  3. Set the vertical offset between the radio buttons by using the spacing variable.

    VBox{
        spacing: 10
        content: choices
    } 
    
     
  4. Use another HBox container to lay out the vertical box with the radio buttons and the horizontal box with the circles.

Note: All the Container classes constrain their children classes to fit a particular size, unlike the Group class that keeps its children size intact. Hence, if you would like to change a size of the RadioButton added to the VBox, its size is not honored, because the container resizes the node to its preferred size. To change the predefined size of the UI control use the LayoutInfo class as follows:

RadioButton{
        toggleGroup: group
        text: text
		layoutInfo: LayoutInfo { width: 150 }
}//RadioButton

See the complete code of the example as follows.

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.ToggleGroup;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.control.RadioButton;
import javafx.geometry.VPos;

def group = ToggleGroup{};
def choiceText = ["STOP", "READY", "GO"];
def colors = ["RED", "GOLD", "GREEN"];

def choices = for (text in choiceText)
RadioButton{
        toggleGroup: group
        text: text
}//RadioButton

def lights = for (color in colors)
Circle {
    centerX: 12
    centerY: 12
    radius: 12
    stroke: Color.DARKGRAY
    fill: bind RadialGradient {
        centerX: 8,
        centerY: 8,
        radius: 12,
        proportional: false
        stops: [
            Stop {offset: 0.0 color: Color.WHITE},
            Stop {offset: 1.0 color:
                    if (choices[indexof color].selected)
                          then Color.web(color)
                          else Color.GRAY
            }//Stop
        ]
    }//RadialGradient
}//Circle

Stage {
    title: "Traffic lights"
    scene: Scene{
	width: 210
        height: 90
        content:
             HBox{                
                spacing: 20
                content:[
                   VBox{ spacing: 10
                         content: choices
                   }
                   HBox{ spacing: 15 content: lights nodeVPos: VPos.CENTER}
                ]
             }//HBox
     } //Scene
}//Stage
 

When compiled and run, this code produces the following window.

A vertical box with radio buttons and a horizontal box with circles

Figure 5: Vertical Box With Radio Buttons and Horizontal Box With Circles
 
Using the Tile Layout

Alternatively you can use another layout manager represented by the Tile class to arrange the same components, but in a slightly different order. The Tile layout arranges elements in a grid of cells. Each cell is exactly the same size. The rows and columns instance variables define the grid's size.

Tile layout

Figure 6: Structure of the Tile Layout
 

To apply the Tile layout:

  1. Add an import statement for the Tile, Insets, and HPos classes.

  2. Add the Tile object literal to the scene's content.

  3. Define the number of rows and columns in the grid.

  4. Use a cycle construction to arrange elements within the grid so that each row contains a radio button and a circle.

  5. Define the amount of horizontal and vertical space between elements by using the hgap and vgap variables.

  6. Specify the top and left padding around the container's contents.

  7. Specify the width of each tile by using the tileWidth instance variable

  8. Set the nodeHPos instance variable to HPos.LEFT to align the elements left.

The following code fragment shows how to create a Tile object with three rows and two columns.


Tile {
	columns: 2
	rows: 3
	tileWidth: 40
	nodeHPos: HPos.LEFT
	padding: Insets{top: 10 left: 10}
	vgap: 5
	hgap: 10
	content: for (i in [0..2])
		[choices[i], lights[i]]
}//Tile
 

See the complete code of the example as follows.

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.RadioButton;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.layout.Tile;
import javafx.geometry.Insets;
import javafx.geometry.HPos;

def group = ToggleGroup{};
def choiceText = ["STOP", "READY", "GO"];
def colors = ["RED", "GOLD", "GREEN"];

def choices = for (text in choiceText)
RadioButton{
        toggleGroup: group
        text: text
}//RadioButton

def lights = for (color in colors)
Circle {
    centerX: 12
    centerY: 12
    radius: 12
    stroke: Color.DARKGRAY
    fill: bind RadialGradient {
        centerX: 8,
        centerY: 8,
        radius: 12,
        proportional: false
        stops: [
            Stop {offset: 0.0 color: Color.WHITE},
            Stop {offset: 1.0 color:
                    if (choices[indexof color].selected)
                          then Color.web(color)
                          else Color.GRAY
            }//Stop
        ]
    }//RadialGradient
}//Circle

Stage {
    title: "Traffic lights"
    scene: Scene{
	    width: 210
            height: 100
            content:

                    Tile {
                          tileWidth: 40
                          nodeHPos: HPos.LEFT
                          padding: Insets{top: 10 left: 10}
                          columns: 2
                          rows: 3
                          vgap: 5
                          hgap: 10
                          content: for (i in [0..2])
                             [choices[i], lights[i]]
                     }//Tile
     } //Scene
}//Stage
 

When compiled and run, the modified application produces the following window.

Tile layout

Figure 7: Tile Layout of the Radio Button and Circles
 

Try to lay out other components, for example, buttons.

Conclusion

In this lesson, you learned how to lay out UI components in a scene. You can use the layout mechanism, absolute coordinates, or a combination of those two approaches for your current task. Refer to the API documentation for more information about layout.

« Previous 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Next »
 
 
 
 
 Photo of Alla Redko
Alla Redko is a technical writer at Sun. She develops documentation for Java SE and JavaFX. Prior to her assignment to Sun, she worked as a technical writer for 10 years.