Skip to main content

Sane JavaFX GUI Code

JavaFX GUI Sanity



JavaFX GUI code can be quite chaotic. Such a situation makes it a challenge to understand the code and to troubleshoot it. 

JavaFX GUIs are simple in concept but if you try hard enough, you can disorganise it. Disorganised code is a sign of confusion which is a sign of deeper malaise....

JavaFX graphic user interfaces can be built up very systematically by following a simple process:

  • All the GUI is contained in a Stage. This Stage constitutes the visible application window though it does not have to be visible.
  • On this stage is placed a Scene which contains Panes to organise and hold GUI controls such as buttons and text boxes. However, bad programming practice allows a programmer to add controls directly to the Scene. The problem with this practice is that there is no way to lay out such controls in a systematic pattern such as horizontal list or in a grid formation.
  • Each Scene can have zero, one or more Panes. Panes can contain other Panes. Most Pane names end with the word Pane such as BorderPane, TilePane, GridPane, FlowPane or AnchorPane. Others like HBox or VBox do not.
  • Panes allow GUI controls to be placed in a systematic patter. The following illustration shows the common JavaFX layout panes.



The relationship between Stage, Scene, Panes and Controls can be illustrated as follows:

The Code...

Building a GUI is like putting up a building: There is some planning, some design and then the construction. They call it software engineering or system analysis and design depending on which school of software thought you belong to. We are at construction stage.

Systematic code will make it easier to get the job done. The following, in my opinion, is an example of well-organised code:

package javafxhandler1;


import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class StackPaneDemo1 extends Application {

    private StackPane stackPane; //Global variable

    @Override
    public void start(Stage primaryStage) throws Exception {
         //Create GUI Controls
            // Create Label
            Label label = new Label("I'm a Label");
            label.setStyle("-fx-background-color:yellow");
            label.setPadding(new Insets(5,5,5,5));   
                
            // Create Button   
            Button button = new Button("I'm a Button");       
            button.setStyle("-fx-background-color: cyan");
            button.setPadding(new Insets(5,5,5,5));
            
            Button controlButton = new Button("Change Top");
               
            // Create CheckBox
            CheckBox checkBox = new CheckBox("I'm a CheckBox");
            checkBox.setOpacity(1);
            checkBox.setStyle("-fx-background-color:olive");
            checkBox.setPadding(new Insets(5,5,5,5));
        
        //Create layouts
        // Create StackPane
        stackPane = new StackPane();
        stackPane.setPrefSize(300, 150);
        stackPane.setStyle("-fx-background-color: Gainsboro;-fx-border-color: blue;");
        //Add controls to StackPane
        stackPane.getChildren().add(label);
        stackPane.getChildren().add(button);
        stackPane.getChildren().add(checkBox);        

        //Create VBox
        VBox root = new VBox();
        VBox.setMargin(stackPane, new Insets(10, 10, 10, 10));
        VBox.setMargin(controlButton, new Insets(10, 10, 10, 10));
        //Add controls/panes to VBox
        root.getChildren().add(stackPane);
        root.getChildren().add(controlButton);
        root.setAlignment(Pos.CENTER);
        
        //Create Scene
        Scene scene = new Scene(root, 550, 250);
        
        //Stage
        primaryStage.setTitle("StackPane Layout Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
        
        //Create Event Handlers
        controlButton.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                changeTop();
            }
        });       
    }

    //Methods 
    private void changeTop() {
        ObservableList<Node> childs = this.stackPane.getChildren();

        if (childs.size() > 1) {
            //
            Node topNode = childs.get(childs.size()-1);
            topNode.toBack();
        }
    }
    
    //Redundant main method - required by some IDEs
    public static void main(String[] args) {
        launch(args);
    }
}

The simple arrangement consists of:

  • GUI Controls
  • Panes
  • Scene
  • Stage
  • Listeners/handlers
  • Methods

The universe is very very orderly and precise for the simple reason that it was created by a very very precise and orderly God. Why reinvent Design? Follow the Designer of designers...Simplify life.

Comments

Popular posts from this blog

How to Run JavaFX 11+ in Intellij IDEA

First published: 8th June 2019 This page explains: 1. How to set up Intellij IDEA with JavaFX 11+ 2. How to configure Intellij IDEA to run JavaFX programs. Follow the links below to download the guides: 1. JavaFX 1 - Installing IntelliJ IDEA and JavaFX 11 Tutorial (8-6-19) 2.  Configure Intellij IDEA to run JavaFX programs

LAMBDA EXPRESSIONS FOR HANDLING EVENTS

Event handlers form the core of any application. They define what happens when you click a button, press a key, select a menu and so on. The discussion on this site demonstrates how to use Lambda expressions to handle events. It is elegant and greatly simplifies your code. The old way of handling a button-click looks like this: Button btn = new Button(); btn.setText("Say 'Hello World'");  btn.setOnAction(new EventHandler<ActionEvent>() {       @Override       public void handle(ActionEvent event)       {           System.out.println("Hello World!");       }  }); The following is a Lambda expression using a "goes to" operator (->): Button button = new Button("Click"); button.setOnAction(value -> { label.setText("Clicked!"); }); Even more elegant: someButton.setOnAction(evt -> someMethod()) Now a greater improvement in programming style: This last format

Android Studio: The Continuing Nightmare [caution, annoyed brother ahead]

If you install Android Studio and it works, consider that a major miracle. Otherwise expect messages like: Gradle doesn't work. Fix you project! [With a saw and hammer, right?] Access denied! Access denied! None of your AVD work so no emulation... FileNotFoundException! - What file please? And does AS expect me to help find it? Why can't YOU find it?  I wish it was kickable - I would give it a very giant KICK. Update! [1.5GB] At lunch - Update! 1GB Evening - Update! Is update some kind of chronic disease or what? And who's going to pay for all these bundles. (9 GB today alone. It's an embarrassment for Google. This thing is like the old steam locomotive: it needs water and wood every few miles. Indexing...………………………………………………………………… an empty project...……………………………………………………. for 30min...……………………………! Get serious Google. If its dead, bury it. Start all over from scratch. AVD won't load Can't find AVD...……….. Java 10.1 is an invalid JDK…………… Can't