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 3: Refactoring Swing JPad's advanced UI features

Migrate Swing JPad's dialogs, clipboard, and drag-and-drop to JavaFX

  • Print
  • Feedback

The refactoring of Swing JPad is well underway, with basic features such as the content pane, menu system, and event handling successfully migrated to JavaFX 2. Now find out how more advanced features such as dialogs and drag-and-drop support map from Swing to JavaFX. Part 3 concludes with Jeff's response to the question of whether JavaFX 2 is production ready, and an opportunity to share your own perspective.

The second part of this article focused on the essential features of a notepad application converted from Swing to JavaFX 2. You've seen how Swing JPad's content pane, menu system, and event handling architecture map to JPadFX. Now, we'll conclude with a look at some of the more advanced features of a notepad application: dialog boxes, a clipboard, and drag-and-drop manipulation.

Dialog boxes

Like the original Swing notepad application, JPadFX presents dialog boxes for selecting a file from the filesystem, showing About information, displaying error messages, and prompting the user for yes/no responses. In Listing 1, JPadFX's start() method instantiates javafx.stage.FileChooser to handle the file-selection task.

Listing 1. Creating and configuring a javafx.stage.FileChooser

fc = new FileChooser();
fc.setInitialDirectory(new File("."));
FileChooser.ExtensionFilter ef1;
ef1 = new FileChooser.ExtensionFilter("TXT documents (*.txt)", "*.txt");
FileChooser.ExtensionFilter ef2;
ef2 = new FileChooser.ExtensionFilter("All Files", "*.*");
fc.getExtensionFilters().addAll(ef1, ef2);

After instantiating FileChooser, start() sets its initial directory to the current one. Because FileChooser offers only a no-argument constructor, the start() method uses fc.setInitialDirectory(new File(".")); instead of a constructor to set the directory.

Continuing, start() creates a pair of extension-based file filters by instantiating FileChooser's nested ExtensionFilter class. It registers them with the file chooser by returning an observable list of extension filters and adding the pair of filters to this list.

JPadFX will use the file chooser to display an Open or Save dialog box by calling FileChooser's void showOpenDialog(Window ownerWindow) or void showSaveDialog(Window ownerWindow) method. Listing 2 demonstrates the former method in the context of JPadFX's doOpenFile(file) method.

Listing 2. Selecting a file to open via showOpenDialog()

if (file == null)
   file = fc.showOpenDialog(stage);
   if (file == null)
      return;
fc.setInitialDirectory(file.getParentFile());

The fc.setInitialDirectory(file.getParentFile()); method ensures that the next file-chooser activation sets the initial directory to the current one.

Unlike JPad, which relies on Swing's JOptionPane class for its About, Alert, and AreYouSure dialog boxes, JPadFX has no JOptionPane equivalent, because JavaFX has yet to provide one. So we'll manually create the About, Alert, and AreYouSure dialog boxes for JPadFX. As you will discover, each dialog box class extends JavaFX's Stage class, which means that a dialog box is nothing more than a secondary stage (as opposed to the primary stage that is passed to the application's start() method).

The About dialog

JPad's About dialog box, which provides information about JPadFX in image and text form, is implemented by the About class. About's source code is shown in Listing 3.

Listing 3. The About class declares only a constructor

public class About extends Stage
{
   public About(Stage owner)
   {
      initOwner(owner);
      initStyle(StageStyle.UNDECORATED);
      initModality(Modality.APPLICATION_MODAL);
      Group root = new Group();
      Image img = new Image(getClass().getResourceAsStream("icon.png"));
      ImageView iv = new ImageView(img);
      double width = iv.layoutBoundsProperty().getValue().getWidth();
      double height = iv.layoutBoundsProperty().getValue().getHeight();
      iv.setX(10.0);
      iv.setY((180.0-height)/2.0);
      root.getChildren().add(iv);
      Text msg1 = new Text("JPadFX 1.0");
      msg1.setFill(Color.WHITE);
      msg1.setFont(new Font("Arial", 20.0));
      msg1.setX(iv.getX()+width);
      msg1.setY(iv.getY()+height/2.0);
      root.getChildren().add(msg1);
      Text msg2 = new Text("by Jeff Friesen");
      msg2.setFill(Color.WHITE);
      msg2.setFont(new Font("Arial", 12.0));
      msg2.setX(msg1.getX());
      msg2.setY(msg1.getY()+20.0);
      root.getChildren().add(msg2);
      Reflection r = new Reflection();
      r.setFraction(1.0);
      root.setEffect(r);
      Scene scene = new Scene(root, 200.0, 180.0, Color.BLACK);
      EventHandler<MouseEvent> ehme;
      ehme = new EventHandler<MouseEvent>()
      {
         @Override
         public void handle(MouseEvent me)
         {
            close();
         }
      };
      scene.setOnMousePressed(ehme);
      setScene(scene);
      setX(owner.getX()+Math.abs(owner.getWidth()-scene.getWidth())/2.0);
      setY(owner.getY()+Math.abs(owner.getHeight()-scene.getHeight())/2.0);
   }
}

In Listing 3, About's constructor takes a Stage argument, which identifies the stage that owns the About dialog box. The About dialog box is owned by the primary stage, so JPadFX passes the primary stage instance to About's constructor via the expression newAbout(stage).show();.

Before the About box is displayed (by calling Stage's void show() method), JavaFX must be informed of this stage's owner. We do this by invoking Stage's void initOwner(Window owner) method with the argument passed to About's constructor.

Next we declare the stage's style and modality. First, we use a void initStyle(StageStyle style) method to inform JavaFX of the desired style for the stage. Calling this method with the javafx.stage.StageStyle enum's UNDECORATED constant tells JavaFX that the stage must not have a border or other decorations.

Next, Stage declares a void initModality(Modality modality) method, which informs JavaFX of the desired modality for the stage. This method is called with the javafx.stage.Modality enum's APPLICATION_MODAL constant, telling JavaFX not to deliver events to any other application window. Both the void initStyle(StageStyle style) and void initModality(Modality modality) methods must be called before the stage is displayed.

Nodes

The constructor next instantiates the javafx.scene.Group class, which is a container node for subsequently created nodes. The first of these nodes is a javafx.scene.image.ImageView instance, which manages a javafx.scene.image.Image instance that describes an image.

  • 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.