Quantcast
Channel: sanjay_dasgupta's blog
Viewing all articles
Browse latest Browse all 10

FX.js - A Smarter FXML Alternative

$
0
0

How many lines of Java do you need to create the following JavaFX application?

HelloWorld-JavaFX

(Answer: About 30, as seen in Hello World, JavaFX Style)

And how many lines of FX.js logo (http://fxjs.java.net/) would you need?

(Answer: See below)

{T: fxStage, title: 'Hello World!',
  scene: {T: fxScene, width: 300, height: 250,
    root: {T: fxStackPane,
      children: [
        {T: fxButton, text: "Say 'Hello World'",
            onAction: function (e) {println('Hello World!');}}
      ]
    }
  }
}

Yet another new format? No, look again ... plain old JavaScript, written with attention to just a few details. If you are even slightly familiar with FXML, the details must be clear already, but if you'd like to see a tutorial, look up the FX.js logo Language Guide.

A lines-of-code comparison with the raw Java in Hello World, JavaFX Style is not really fair, so lets move on to a comparison with some full-blooded FXML. But first a quick guided tour to help you understand the example ...

But wait, there's more!

The FX.js logo script shown above has a JavaScript function labelled onAction to handle button events. But how can you have code executed at startup?

{T: fxStage, title: 'Hello World!', 
  scene: {T: fxScene, fxid: 'theScene', width: 300, height: 250,
    root: {T: fxStackPane,
      children: [
        {T: fxButton, text: "Say 'Hello World'",
            onAction: function (e) {println('Hello World!');}}
      ]
    }
  },

  main: function (args) {
    if (args.length > 0) {
      importPackage(Packages.javafx.scene.paint);
      this.theScene.setFill(Paint.valueOf(args[0]));
    }
  }
}

The main(args) function is executed at startup. It expects one command-line argument, the name of a color (that Paint.valueOf() can recognize), and sets the background of the Scene to that color. We added "fxid: 'theScene'" to the Scene object to give it a name that main() can access. The following table shows the effect of running the script with skyblue and khaki respectively as a command-line argument.

java -cp ... fxjs.Main sample.js skybluejava -cp ... fxjs.Main sample.js khaki
skybluekhaki

Incidentally, if you are a JavaScript guru frowning at the "importPackage(...);", you should take a lesson about a part of the JVM that is as threatened by neglect as its critically endangered namesake is by man's superstition and greed.

You can also add other application-specific functions and/or data alongside main() (or in place of it). Code in functions and event-handlers can access these functions and data using the "this.name" notation.

When you use FX.js logo the entire application lives in one file, no separate XML for the GUI, no Java launchers, stubs or glue files, and no build files to assemble everything. Just one warm and fuzzy ball of JavaScript. But if you need to, it's always possible to call out to Java as described in Application Architectures. You can find a bunch of FX.js logo examples in More UI Examples.

Before moving on to the FXML comparison let's quickly find out how a FX.js logo script is run.

Running a FX.js logo Script

Instructions for running a FX.js logo script can be found in the Quick Start Guide.

An FXML Comparison

Here is the FX.js logo translation of the application in Using FXML to Create a User Interface.

{T: fxStage, title: "JavaFX Welcome",
  scene: {T: fxScene, width: 300, height: 275,
    root: {T: fxGridPane, vgap: 10, hgap: 10, alignment: fxCENTER,
        padding: {T: fxInsets, top: 25, right: 25, bottom: 25, left: 25},
        stylesheets: "file:Login.css",
      children: [
        {T: fxText, id: "welcome-text", text: "Welcome",
            font: {T: fxFont, name: "Tahoma", size: 20},
            rowIndex: 0, columnIndex: 0, columnSpan: 2, rowSpan: 1},
        {T: fxLabel, text: "User Name:", rowIndex: 1, columnIndex: 0},
        {T: fxTextField, rowIndex: 1, columnIndex: 1},
        {T: fxLabel, text: "Password:", rowIndex: 2, columnIndex: 0},
        {T: fxPasswordField, rowIndex: 2, columnIndex: 1},
        {T: fxHBox, spacing: 10, rowIndex: 4, columnIndex: 1,
            alignment: fxBOTTOM_RIGHT,
            children: [{T: fxButton, text: "Sign in", onAction: function (e) {
                this.actiontarget.setFill(fxFIREBRICK);
                this.actiontarget.setText("Sign in button pressed");}}]},
        {T: fxText, fxid: "actiontarget", rowIndex: 6, columnIndex: 1},
      ]
    }
  }
}

Before trying to run this example, copy Login.css and background.jpg into the directory containing the script.

The FXML approach uses three separate files, and a number of naming and coding conventions that must be used to express the linkages between them. Which do you prefer?

The FX.js logo Project

An open-source project for FX.js logo has been started at "http://fxjs.java.net/". The interpreter, source-code, documentation, and sample applications are available at the project site. The volume of documentation and examples is still growing, but there's already enough to help you get started. Take a look!

Curious about the name?

Like many other parents (that live on my side of the planet), I consulted the recommended lists, books, astrological sites, and sundry quacks, and narrowed things down to guise and disguise. Both contained "gui", and were strangely mysterious enough to satisfy the eastern penchant for unusual names. But guise was too similar to guice. And, though the gui in disguise was a neat hint, it didn't really show that the newborn was destined to follow in the footsteps of systems that use JavaScript in unexpected ways. Long live FX.js logo!


Viewing all articles
Browse latest Browse all 10