Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Practical JavaFX 2, Part 2: Refactoring Swing JPad's basic UI features to JavaFX

Migrate JPad's content pane, menu system, and event handling to JavaFX

  • Print
  • Feedback

Page 2 of 6

Architecture of JPadFX

JPadFX consists of About, Alert, AreYouSure, and JPadFX classes. JPadFX is the main class, as shown in Listing 1, and the other classes implement custom dialog boxes.

Listing 1. The JPadFX class drives the JPadFX application

// ...
public class JPadFX extends Application
{
   // ...
   @Override
   public void start(final Stage primaryStage)
   {
      // ...
      Application.Parameters params = getParameters();
      List<String> uparams = params.getUnnamed();
      if (uparams.size() != 0)
         doOpen(new File(uparams.get(0)));
   }
   private void doExit(Event e)
   {
      // ...
   }
   private void doNew()
   {
      // ...
   }
   private void doOpen()
   {
      doOpen(null);
   }
   private void doOpen(File file)
   {
      // ...
   }
   private boolean doSave()
   {
      // ...
   }
   private boolean doSaveAs()
   {
      // ...
   }
   private String read(File f) throws IOException
   {
      // ...
   }
   private void write(File f, String text) throws IOException
   {
      // ...
   }
   public static void main(String[] args)
   {
      launch(args);
   }
}

Listing 1 reveals a skeletal framework that is very similar to the original Swing JPad architecture, but there are some differences. Unlike JPad, which extends Swing's JFrame class, JPadFX extends the javafx.application package's abstract Application class. Application declares methods for launching JavaFX applications, for defining the application's lifecycle, and more.

In Listing 1, Application declares the void launch(String... args) class method to launch the application. This method is passed the array of command-line arguments and then instantiates the application class, JPadFX.

Next, Application's void init() method is called on a thread known as the launcher thread. If you wanted to, you could override this method to perform initialization before the application started, but JPadFX doesn't do that.

Sometime after init() returns, Application's void start(Stage primaryStage) method is invoked on the JavaFX application thread. This method is invoked with a javafx.stage.Stage instance and is used to construct and display the UI.

A Stage instance is a container for an application's UI. Because Stage extends the javafx.stage.Window class, Stage instances are also Window instances that can be shown and managed. Applications can have multiple Stages; additional instances can serve as dialog boxes.

The application runs until its last stage window is closed, either by the user or via the javafx.application.Platform class's void exit() class method. JavaFX responds by calling Application's void stop() method on the JavaFX application thread. This method gives an application a chance to release any previously acquired resources. Because JPadFX doesn't need to release any resources, JPadFX does not override stop().

stop() and resource disposal

Use stop() to release resources acquired in init() and/or start(). Because init() runs on the launcher thread and stop() runs on the JavaFX application thread, fields referring to init()-acquired resources must be declared volatile.

After creating JPadFX's UI, start() opens the file identified by the first command-line argument when at least one argument is specified. However, its approach to obtaining this argument differs from the simple approach taken by JPad's constructor.

JavaFX applications can access parameters specified as command-line arguments, unnamed parameters, name/value pairs in JNLP (Java Network Launching Protocol) files, and so on. Application declares an Application.Parameters getParameters() method for accessing all of these possibilities.

Parameters declares Map<String, String> getNamed(), List<String> getRaw(), and List<String> getUnnamed() methods to access all, named, and unnamed parameters. start() calls the latter method because command-line arguments are unnamed.

Creating the UI

JPadFX's start() method creates JPadFX's UI by constructing a scene graph of nodes. A scene graph is a tree of nodes, which represent a UI's visual and nonvisual elements (such as controls and layouts). Collectively, these elements describe a scene. Listing 2 shows how JavaFX 2 organizes the JPadFX UI into a scene.

Listing 2. JPadFX's UI is created in the start() method

// ...
private TextArea ta;
private Label lbl;
// ...
public void start(final Stage primaryStage)
{
   // ...
   BorderPane root = new BorderPane();
   MenuBar mb = new MenuBar();
   Menu mFile = new Menu("File");
   MenuItem miNew = new MenuItem("New");
   KeyCharacterCombination kccNew;
   kccNew = new KeyCharacterCombination("N", KeyCombination.CONTROL_DOWN);
   miNew.setAccelerator(kccNew);
   // ...
   mFile.getItems().add(miNew);
   // ...
   mb.getMenus().add(mFile);
   // ...
   Menu mFormat = new Menu("Format");
   final CheckMenuItem cmiWordWrap = new CheckMenuItem("Word Wrap");
   // ...
   mFormat.getItems().add(cmiWordWrap);
   // ...
   mb.getMenus().add(mFormat);
   // ...
   root.setTop(mb);
   root.setCenter(ta = new TextArea());
   // ...
   root.setBottom(lbl = new Label("JPadFX 1.0"));
   Scene scene = new Scene(root, 400, 400, Color.WHITE);
   primaryStage.setScene(scene);
   primaryStage.setTitle(DEFAULT_TITLE);
   // ...
   primaryStage.show();
   // ...
}

In Listing 2 we see JPadFX's start() method first instantiate javafx.scene.layout.BorderPane, a container managed by a java.awt.BorderLayout-style layout manager. JPadFX uses BorderPane to organize its controls and to serve as the root node of its scene graph.

BorderPane reveals a significant difference between JavaFX and Swing. Unlike Swing's BorderLayout, which focuses on layout management only, BorderPane combines layout management with containment. JavaFX blends these concepts to simplify UI development. Another blending example is javafx.scene.layout.GridPane, which is JavaFX's counterpart to java.awt.GridLayout.

Menus in JavaFX versus Swing

After instantiating BorderPane, start() creates the menu bar and menus by working with the javafx.scene.control.MenuBar, javafx.scene.control.Menu, javafx.scene.control.MenuItem, and javafx.scene.control.CheckMenuItem classes.

Although the JavaFX code in Listing 2 shows some similarities to a Swing-based menu structure, you've surely noted some differences. For one, we would typically use a javax.swing.KeyStroke instance to set a menu item's accelerator in Swing, as shown in Listing 3.

Listing 3. Setting a menu item's accelerator in Swing

miNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK));

But in JavaFX we use javafx.scene.input's KeyCharacterCombination and KeyCombination classes to acquire the accelerator key, as shown in Listing 4.

  • Print
  • Feedback

Resources

More from JavaWorld

  • Find more of Jeff's writing in Java Tutor, his blog on JavaWorld.
  • See the JavaWorld Site Map for a complete listing of research centers focused on client-side, enterprise, and core Java development tools and topics.
  • JavaWorld's Java Technology Insider is a podcast series that lets you learn from Java technology experts on your way to work.