Designing a Sign In Window with JavaFX

Designing a Sign In Window in Scene Builder

I want to create a Sign In window where the user can enter the id, password and press the button Sign In. The scene will use GridPane layout. The first row will contain a Label and TextField for user id, the second row will have a similar pair for the password, and the third row of the grid will have one Button Sign In that should span two columns. This is how this window should look like:

fig 7 07
Figure 56. The Sign In Window

I’ll start with creating a new IDEA JavaFX project (menus File | New Project | JavaFX Application) giving it the name Signin. The project with classes Main, Controller and the file sample.fxml will be generated. Let’s rename this FXML file into signin.fxml. IDEA will automatically change the corresponding line in the Main class to load this file instead of sample.fxml:

Parent root = FXMLLoader.load(getClass().getResource("signin.fxml"));

Rename the package from sample to signin (right-click menu, Refactor | Rename). Now open the file signin.fxml in Scene Builder and start thinking about laying out the components of our Sign In scene. Let’s take another look at the image of the Sign In window. I can clearly see that GUI components are placed in three rows. The first two have a Label and TextField and the third one has a wide Button. I can also recognize two columns in the layout of the Sign In window. The first column has two Label components and the left side of the Button. The second column has two TextFiled components and the right side of the Button. We can also say that the Button spans two columns. We’ve got a 2×3 grid!

Open the generated signin.fxml in Scene Builder. Since this file has already empty <GrigPane> tag, you’ll see GridPane(0,0) as the root of the hierarchy in the bottom left corner as in Figure 4 above. So far this grid has zero rows and zero columns. Right-click on the grid in the middle of the screen and add three rows and two columns to the grid by using the right-click menus GridPane | Add Row Below and Add Column After. When the GridPane is selected The Scene Builder’s window may look similar to this:

fig 7 08
Figure 57. A GridPane (2,3)

Now let’s drag two Label controls and a Button from the Controls section on the left and drop them into the appropriate cells in the first grid column. Change the text on these components to be UserID:, Password, and Sign In. Then we could drag and drop two TextField objects in the top two cells in the second column. Actually, it’s not a good idea to enter password in the clear text. I’ll use the TextField for the user ID, and the PasswordField (it marks user’s input) for password.

fig 7 09
Figure 58. A GridPane with nodes in Scene Builder

Note that the hierarchy of nodes is shown in the bottom left panel of Scene Builder. If you want to change the properties of a component on a scene with a complex GUI layout it might be easier to select the GUI control in the Hierarchy panel than in the design area in the middle. Now select the menu Preview | Show Preview in Window and you’ll see the following window:

fig 7 10
Figure 59. Previwing in Scene Builder

This window doesn’t look exactly as we wanted: there are some issues with alignments, there is no spacing between the container and components, and the button Sign In doesn’t span. But on the bright side, the GridPane controls the layout and if you’ll try to stretch this window, GUI components won’t change their relative positioning:

fig 7 11
Figure 60. Streching the preview window in Scene Builder

Let’s do a couple of more property changes before we’ll run this application from IDEA. In Scene Builder the Properties panel is located on the right and has three sections: Properties, Layout, and Code, and you’ll find the properties to be changed in one of these sections.

  1. On the left panel of Scene Builder select the GridPane and on the right panel change alignment to be TOP_LEFT.
  2. Enter 10 for the padding on top, right, bottom and left for the GridPane. We need some spacing between the borders of the scene and the grid.
  3. Select the Button on the left and then change the column span to be 2 and the preferred width to be a large number, say 300. This will make the button wide.
  4. Select the first column of the grid row by clicking on the little 0 on top of the grid. Set the both preferred and maximum width for this column to be 70.
  5. Select the second column of the grid row by clicking on the little 1 on top of the grid. Set the both preferred and maximum width for this column to be 100.

After you do all these changes and save them, the file signin.fxml will look like this:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>

<GridPane hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="signin.Controller">
   <rowConstraints>
      <RowConstraints minHeight="10.0" prefHeight="30.0" />
      <RowConstraints minHeight="10.0" prefHeight="30.0" />
      <RowConstraints minHeight="10.0" prefHeight="30.0" />
   </rowConstraints>
   <columnConstraints>
      <ColumnConstraints maxWidth="70.0" minWidth="10.0" prefWidth="70.0" />
      <ColumnConstraints maxWidth="100.0" minWidth="10.0" prefWidth="100.0" />
   </columnConstraints>
   <children>
      <Label alignment="CENTER" text="User ID:" />
      <Label text="Password:" GridPane.rowIndex="1" />
      <Button mnemonicParsing="false" prefWidth="300.0" text="Sign In" GridPane.columnSpan="2" GridPane.rowIndex="2" />
      <TextField GridPane.columnIndex="1" />
      <PasswordField GridPane.columnIndex="1" GridPane.rowIndex="1" />
   </children>
   <padding>
      <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
   </padding>
</GridPane>

In the <GridPane> section you see <rowConstraints> and <columnConstraints> tags defining the the properties of the rows and columns. The <children> section contains the declaration of GUI components that the user will see on the screen: <Label>, <Button>, <TextField>, and <PasswordField>. The <Insets> section ensures that there is some space between the grid borders and its children.

This is a declarative way of creating GUI in FXML. No Java coding was required to create the GUI for this application.

Finally, let’s set the size of the stage so it can accommodate all components from our scene. In IDEA, open the class Main, and in the code set the size of the scene to be 200×150 pixels.

primaryStage.setScene(new Scene(root, 200, 150));

Run the Main program and you’ll see the window that looks similar to the one in Figure 7 above. The work that we’ve done in Scene Builder was a little tedious, but it didn’t require any knowledge of Java. This means that this work can be given to a UI designer, while you’ll concentrate on programming the application logic in Java.

Styling With CSS

It would be boring if all applications would look the same. Application windows may have different colors, fonts, buttons with rounded corners or use special visual effects. In other words, applications have different styles. Even though you can style JavaFX GUI components programmatically (e.g. by calling methods setFont() or setFill()) separating styling from programming allows professional UI designers to take care of the look and feel while software developers implement application logic.

Separating the work of programmers and designers became popular in Web applications. Cascading Style Sheets (CSS) is a special language for styling UI. Styles of GUI components are stored in separate .css files and are loaded and applied to components by the application’s code. Sometimes this process is called skinning – you can create an application that can “wear different skins” changing its look to the user’s liking. JavaFX has a default skin, and if you’re interested in how to create custom skins, visit Oracle online tutorial Skinning JavaFX applications with CSS.

Even if you won’t create your own CSS file, your JavaFX application applies default CSS style to the components of your view. In Scene Builder you can see these styles. Just select any component and then go to the menu View | Show CSS Analyzer. You’ll see a number of styles the start with the prefix fx-, which makes JavaFX CSS a little different from a standard CSS syntax.

Covering CSS in detail would require a separate book, but I’ll show you a simple example of how the look of the GUI can be changed without the need to modify the Java code.

You can either create so-called CSS selectors to style a specific GUI component, a type of components (e.g. all buttons), or create a reusable style that can be applied programmatically to a selected component.

To style a specific component it has to have a unique id. If you program GUI in Java, set in your Java code using the method setId(), for example:

Button signInBtn = new Button ("Sign In");
signInBtn.setId("submitBtn");

In FXML just add an id attribute to the tag of the component:

<Button id="submitBtn" text="Sign In">

For a button with an id submitBtn you can add the following section to the CSS file to make its background color red:

#submitBtn{
  -fx-background-color: red;
}

You can find the names of the main CSS colors online. In CSS the id type selectors start with the #-sign as in #submitBtn.

If you want to apply a style to several components of the same type, you need to define a type selector. For example, to make the text of all Label components red, you can define the following CSS type selector:

.label{
  -fx-text-fill: red;
}

Note that CSS type selectors start with the dot. To create a CSS class selector that can be applied to any component, define the selector with an arbitrary name and apply it programmatically to the components of your choice. For example, you can specify the class selector .blueLable:

.bluelabel{
   -fx-text-fill: blue;
   -fx-font-family:verdana;
   -fx-font-style:italic;
}

This class selector defines the rules that will display text of the component in blue bold verdana font in italic style. Typically, you’ll be loading the entire CSS file when the application starts so all styles are available for use. If you use Java for GUI programming, you can apply a class selector to a specific button just like this:

Label userPwdLbl = new Label("Password:");
userPwdLbl.getStyleClass().add("bluelabel");

In FXML assigning a CSS class selector is done by adding the attribute styleClass to the tag element:

<Label text="Password:" styleClass="bluelabel" GridPane.rowIndex="1" />

You may ask, “How am I supposed to know which style properties are available for a given JavaFX component?” All JavaFX styles are described in the online document titled “JavaFX CSS Reference Guide”.

Let’s learn how to apply all these styling techniques to the Sign In window from the previous section. Using IDEA menu File | New create a new file signin.css in Signin project. Then add the following content to it:

#submitBtn{
    -fx-background-color: lightskyblue;
    -fx-font-family:verdana;
    -fx-font-size:20;
    -fx-font-weight: bold;
    -fx-stroke:navy;
    -fx-font-style:italic;
    -fx-border-radius: 20;
    -fx-background-radius: 20;
    -fx-padding: 5;
}

.label{
    -fx-text-fill: red;
}

.bluelabel{
   -fx-text-fill: blue;
   -fx-font-family:verdana;
   -fx-font-style:italic;
}

The file signin.css defines three styles:

  • an id selector for the component with the id submitBtn
  • a type selector for all Label components
  • a class selector bluelabel that can be applied to certain labels.

To apply this CSS file to our Sign In application add the attribute id="submitBtn" to the <Button> element in signin.fxml.

Then add the attribute styleClass="bluelabel" to the <Password> tag in signin.fxml.

Finally, in Main.java load the signin.css and apply it to the scene. The new version of Main.java will look like this:

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("signin.fxml"));
      primaryStage.setTitle("Sign In");

      Scene scene  = new Scene(root, 200, 150);
        scene.getStylesheets().add(getClass()
              .getResource("signin.css").toExternalForm());

      primaryStage.setScene(scene);
      primaryStage.show();
    }


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

Run the Main application and you’ll see a differently styled Sign In window:

fig 7 12
Figure 61. Styled Sign In Window

When the application starts loading our CSS file it sees that all labels must be red because of the type selector for labels. But then the application notices a more specific style for the Label Password: styleClass="bluelabel", so it paints the text Password in blue.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s