Saturday 26 December 2015

Properties pane (I)

As I want to use JavaFX on already existing applications I am in the process of investigating how to improve those applications with pieces of JavaFX.

One improvement is handling properties. JavaFX allows to create property panels in a neat way. But let's start from the beginning.

For the sake of the example I am going to use an text property, a boolean property and a filename property.

The FXML file 'properties.fxml' is as follows.
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<GridPane hgap="10.0" vgap="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
  <columnConstraints>
    <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" />
    <ColumnConstraints hgrow="SOMETIMES" />
    <ColumnConstraints hgrow="SOMETIMES" />
  </columnConstraints>
  <rowConstraints>
    <RowConstraints vgrow="SOMETIMES" />
    <RowConstraints vgrow="SOMETIMES" />
    <RowConstraints vgrow="SOMETIMES" />
  </rowConstraints>
   <children>
     <Label text="Text property" />
     <Label text="Boolean property" GridPane.rowIndex="1" />
     <Label text="File property" GridPane.rowIndex="2" />
     <TextField fx:id="textProperty" prefHeight="25.0" prefWidth="74.0" GridPane.columnIndex="1" GridPane.columnSpan="2" />
     <RadioButton fx:id="boolProperty" minHeight="25.0" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="1" />
     <TextField fx:id="fileProperty" GridPane.columnIndex="1" GridPane.rowIndex="2" />
     <Button mnemonicParsing="false" onAction="#onSelect" text="Select" GridPane.columnIndex="2" GridPane.rowIndex="2" />
    </children>
   <padding>
     <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
   </padding>
</GridPane>
For this pane the properties are aligned in rows inside a grid. The labels are in the first column aligned to the right and the fields are in the second column. For the filename field a Select button is provided splitting the second column in two.

Then the main class is created in file "Properties.java"
import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.Parent;
import javafx.stage.Stage;

/**
 * @author António Raposo
 */
public class Properties extends Application {

   @Override
   public void start(Stage primaryStage) throws IOException {
      Parent root = FXMLLoader.load(getClass().getResource("properties.fxml"));
      Scene myScene = new Scene(root);
      primaryStage.setScene(myScene);
      primaryStage.show();
   }

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

} 
It's very similar to the previous Hello example. But for this example there is also a controller in file "Controller.java"
import java.io.File;
import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; import javafx.stage.FileChooser; /** * @author António Raposo */ public class Controller { @FXML private TextField textProperty; @FXML private RadioButton boolProperty; @FXML private TextField fileProperty; @FXML void onSelect(ActionEvent event) { FileChooser chooser = new FileChooser(); chooser.setTitle("Select File"); File file = new File(fileProperty.getText()); chooser.setInitialDirectory(file.getParentFile()); File newfile = chooser.showOpenDialog(fileProperty.getScene().getWindow()); if (newfile != null) { fileProperty.setText(newfile.getAbsolutePath()); } } }
And that's it. Just compile and run. Here is how it looks.


For the moment there is no way to load and save the properties. That will be the next step.

Friday 18 December 2015

Hello JavaFX (8)

Introduction

Once upon a time, there was a blog called "A Cup of Java". Until one day the service where it was hosted shut down.

JavaFX ended up being the trigger that send me to find another blog service and start writing again.

I've been using Java and Swing for ages, but I always felt awkward building user interfaces in code, mixing them with event handlers and ending up with either an entire constellation of small classes or a hipper huge unmanageable class. Sometimes it worked well, others it became close to unmanageable.

Of course, JavaFX is not going to replace Swing but has some features I like. Of course, it is still possible to build an entire JavaFX user interface programmatically and assign a multitude of controllers to it. But the beauty of it is that it is possible to entirely separate the user interface from the code. Writing the interface in FXML allows one to easily design the user interface without the temptation of starting to code. It also has some new and very useful containers and as a bonus finally brings charts!

Having that itching in my hands to try it I started to re-write a small app I had made using Swing and a third-party charts library. The result was good, becoming much simpler than the original and working equally well but better looking.

Overview

In this article, I'll explain how to start writing applications using JavaFX and try a very simple example.

How to create a JavaFX application

My recipe for JavaFX is as follows:
  • Build the user interface in FXML.
  • Create a controller class like MyAppController.
  • Create the main class like MyApp extending Application.
Let's do a hello world example

First step: create the FXML and save it as "hello.fxml":
<?xml version="1.0" encoding="UTF-8"?>

<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<StackPane>
   <Label text="Hello World"/>
</StackPane>
Second step: this example has no interactions so there is no need for a controller, skip this step.
Third step: create the main class Hello and save it as "Hello.java":
import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.Parent;
import javafx.stage.Stage;

/**
 * @author António Raposo
 */
public class Hello extends Application {

   @Override
   public void start(Stage primaryStage) throws IOException {
      Parent root = FXMLLoader.load(getClass().getResource("hello.fxml"));
      Scene myScene = new Scene(root);
      primaryStage.setScene(myScene);
      primaryStage.setWidth(400);
      primaryStage.setHeight(300);
      primaryStage.show();
   }

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

}
Now compile and run. Here is how it looks.

Conclusion

If you followed these steps you just created your first JavaFX application.