JavaFX Mobile

June 24, 2009

Asynchronicity in JavaFX 1.2

200px-Police-album-synchronicity The asynchronous task model has been much improved in JavaFX 1.2.  Not only does it have a simple and elegant API, but several of the asynchronous tasks (e.g. HttpRequest) in the JavaFX API now use this model.  In addition, there are a couple of progress UI controls introduced in JavaFX 1.2, and they work well with the new asynchronous model.

The JavaFX package that contains the asynchronous-related classes is javafx.async, and a good class to take a look at first is JavaTaskBase.  This class enables you to start a task, check on its progress, and be notified when the task has completed.  JavaFX is single threaded, so the task that is started is one that you define in a Java class (that implements the javafx.async.RunnableFuture interface).  The Java class can then call functions of your JavaFX classes, demonstrating bi-directional integration between JavaFX and Java.

Take a look at the screenshot of a simple example on which Stephen Chin and I collaborated, that demonstrates the capabilities just described:

Async_progressbar

Clicking on the Start the Task button starts a new task and adds a ProgressBar into the scene (up to a maximum of eight, the built-in limit on the number of tasks in JavaFX that can be run in parallel).  When a task completes, its ProgressBar is removed from the scene.  Take a look at the AsyncProgressMain.fx script below to understand how the UI is drawn, and how the tasks are started:

package projavafx.asyncprogress.ui;

import projavafx.asyncprogress.model.*;

import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

var vbox:VBox;

function startTask() {
  def progressBar:ProgressIndicator = ProgressBar {
    progress: bind taskController.floatProgress
  }

  def taskController:TaskController = TaskController {
    maxProg: 100
    onStart:function():Void {
      insert progressBar into vbox.content;
    }
    onDone:function():Void {
      delete progressBar from vbox.content;
    }
  }
  taskController.start();
}

Stage {
  title: "Async and Progress Example"
  scene: Scene {
    width: 200
    height: 250
    content: vbox = VBox {
      layoutX: 10
      layoutY: 10
      spacing: 10
      content: [
        Button {
          text: "Start the task"
          action: function():Void {
            println("Starting TaskController");
            startTask();
          }
        }
      ]
    }
  }
}


Now take a look at the TaskController class that is instantiated in the script above when the button is clicked:

package projavafx.asyncprogress.model;

import projavafx.asyncprogress.model.Ticker;
import javafx.async.RunnableFuture;
import javafx.async.JavaTaskBase;

public class TaskController extends JavaTaskBase, TickerHandler {
  public var maxProg:Integer;
  public-read protected var floatProgress:Number;

  override public function create():RunnableFuture {
    maxProgress = maxProg;
    return new Ticker(this);
  }

  override public function onTick(tickNum:Integer):Void {
    progress = tickNum;
    floatProgress = percentDone / 100.0;
  }
}

Note that the TaskController class above extends the JavaTaskBase class mentioned earlier.  We'll use its capabilities to start and monitor the task.  When the create function of the TaskController instance is called by the JavaFX runtime (as a result of its start function being called) it creates a new instance of the Ticker class that we developed in Java.  As shown in the code below, the Ticker class implements the RunnableFuture interface mentioned earlier.

package projavafx.asyncprogress.model;

import com.sun.javafx.functions.Function0;
import javafx.lang.FX;
import javafx.async.RunnableFuture;

public class Ticker implements RunnableFuture {
  TickerHandler tickerHandler;

  public Ticker (TickerHandler tickerHandler) {
    this.tickerHandler = tickerHandler;
  }

  @Override public void run() {
    for (int i = 1; i <= 100; i++) {
      if (tickerHandler != null) {
        final int tick = i;
        FX.deferAction(new Function0<Void>() {

           @Override public Void invoke() {
             tickerHandler.onTick(tick);
             return null;
           }
        });
      }
      try {
        Thread.sleep(200);
      }
      catch (InterruptedException te) {}
    }
    System.out.println("Ticker#run is finished");
  }
}


The Ticker class shown above counts to 100, sleeping for a couple hundred milliseconds each iteration.  During each iteration it calls the onTick function of the TaskController class shown previously, which implements the TickerHandler interface.  Here's the code for that interface:

package projavafx.asyncprogress.model;

public interface TickerHandler {
  void onTick(int tickNum);
}


For an excellent explanation (including UML sequence diagrams) of asynchronous tasks in JavaFX, see Baechul's JavaFX 1.2 Async blog post.  Also take a look at the Richard Bair and Jasper Potts fxexperience.com post on the subject.

For those interested in JavaFX Mobile, here's a short video clip of this example running on an HTC Diamond phone.  You may want to mute the audio, as I didn't mute the microphone when creating this video. ;-)

Async_progressbar_mobile

As I mentioned in the dynamic Timeline values post, I'm trying to encourage you to compile and run the examples in this blog.  However, please leave a comment if you'd like a Java Web Start link. 

Regards,

Jim Weaver

April 27, 2009

JavaFX Performance Tips from Michael Heinrichs

Greasy_fast_speed There is a scene in Rocky II in which boxing trainer Mickey tells Rocky something to the effect of: We need speed. Speed's what we need. Greasy, fast speed!

Today I'd like to feature some JavaFX performance tips that Michael Heinrichs documented in his article entitled JavaFX Mobile Applications - Best Practices for Improving Performance.  This article points out some performance-related lessons learned while preparing the JavaFX Mobile release:

  • Avoid unnecessary bindings
  • Keep the scenegraph as small as possible
  • Use simple shapes instead of images
  • Use the pre-scaling functionality
  • Use background loading
  • Use Integer instead of Number
  • Use functions of class Sequences

The tips in the article are not only valid for JavaFX Mobile, but for JavaFX on other platforms as well.  Michael does a great job in explaining these tips, as well as using short code examples to make them easy to understand and implement.

Penguin As a random bit of trivia, did you know that the Mickey character shown above in the Rocky series was played by the same actor as The Penguin in the Batman television series?  Yup, they were both played by the late [Oliver] Burgess Meredith :-)

Regards,
Jim Weaver

March 02, 2009

Pro JavaFX Released in Apress Alpha (Early Access) Program

Pro-javafx-alpha As many of you know, Weiqi Gao, Stephen Chin, Dean Iverson and I have been writing a book entitled  Pro JavaFX that is targeted at serious developers who want to use JavaFX.  In addition to the book being available in printed form by JavaOne 2009, we made the decision last week to allow the book to be offered as an Apress Alpha (early access) eBook.  This enables you to see the chapters of the book as drafts are submitted and revised, which gives you access to the content as soon as it is created (typos and all).  This also enables us to fine-tune the material based upon your feedback.

Here's the list of the chapters for the book:

  1. Getting a Jump Start in JavaFX
  2. Taking a Closer look at the JavaFX Language
  3. Creating a User Interface in JavaFX
  4. Using Functions, Classes and Other Advanced Features
  5. Creating Custom UI Components in JavaFX
  6. Using the Media Classes
  7. Dynamically Laying out Nodes in the User Interface
  8. Extending JavaFX with Third-Party Libraries
  9. Building a Professional JavaFX Application
  10. Developing JavaFX Mobile Applications

Currently, seven chapters (1, 2, 3, 4, 6, 7, 8) are available for download, and each of these is in first or second draft.  Chapters 5, 9 and 10 will be available soon as first drafts.  Here is a screenshot from Chapter 8 in which a drawing program built in JavaFX (in Chapter 5) is used to draw the shapes available in the JFXtras project:

DrawJFXtras

Weiqi, Stephen, Dean and I welcome you to join us in this journey as we complete the development of what is becoming a definitive treatment of JavaFX for professional developers.

For therapeutic purposes I'm sure, Stephen Chin wrote a quick blog post that gives an "exclusive, behind-the-scenes look into the making of the Pro JavaFX™ Platform book" :-)

Regards,
Jim Weaver
JavaFXpert.com

February 13, 2009

JavaFX 1.1 Mobile Example: Using Binding and Key Events

Now that JavaFX SDK 1.1 has been released, which includes JavaFX Mobile, I wanted to show you a couple of code examples along with Java Web Start links to run them.  Note: This is an update to a pre-JavaFX 1.1 article posted earlier.

BindingExampleMobile1-1

Webstart.small2

The screenshot above is a simple example of binding, running in the JavaFX Mobile emulator, that uses UI capabilities that exist on the JavaFX Mobile platform.  It also demonstrates handling mouse and key events.  Click on the screenshot or Launch button above to run this example via Web Start.  A little later in this post I'll expand the example to create a UI that behaves somewhat like graphic equalizer controls. Take a look at the code for this example:

/*
* MobileBindingMain.fx
*
* Developed 2009 by James L. Weaver to demonstrate binding in JavaFX
* with UI classes in the JavaFX Mobile profile, and keyboard input.
*/

package projavafx.mobilebinding.ui;

import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.text.*;

var level:Number = 30;
def MAX_LEVEL:Number = 230;
def MIN_LEVEL:Number = 10;
var rectRef:Rectangle;

Stage {
  title: "Binding Example"
  scene: Scene {
    fill: Color.BLACK
    width: 240
    height: 320
    content: [
      Text {
        translateX: 20
        translateY: 20
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: "Binding / KeyEvent 1"
        fill: Color.WHITE
      },
      rectRef = Rectangle {
        x: 0
        y: 60
        width: bind level
        height: 20
        fill: LinearGradient {
          startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
          stops: [ Stop { offset: 0.0 color: Color.LIGHTBLUE },
               Stop { offset: 1.0 color: Color.DARKBLUE } ]
        }
        onMouseDragged: function(me:MouseEvent):Void {
          if (me.x >= MIN_LEVEL and me.x <= MAX_LEVEL) {
            level = me.x;
          }
        }
        onKeyPressed: function(ke:KeyEvent):Void {
          if (ke.code == KeyCode.VK_RIGHT and level <= MAX_LEVEL - 10) {
            level += 10;
          }
          else if (ke.code == KeyCode.VK_LEFT and level >= MIN_LEVEL + 10) {
            level -= 10;
          }
        }
      },
      Text {
        translateX: 20
        translateY: 100
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: bind "Level: {level}"
        fill: Color.WHITE
      }
    ]
  }
}
rectRef.requestFocus();

The length of the bar can be adjusted by clicking in the bar and dragging the mouse.  It can also be adjusted by pressing the left and right arrow keys, either on the computer keyboard or on the mobile emulator.  As shown in the listing above, the width of the rectangle is bound to the value of the level variable.

The next example uses a sequence of values to which the bars in the graphic equalizer are bound.  Like the previous example, the length of a bar can be controlled by dragging it or pressing the right and left arrow buttons.  In addition, the bar to be adjusted can be selected by pressing the up and down arrow keys, as well as clicking it with the mouse.  Here's a screenshot of the UI running in the JavaFX Mobile emulator:

EqualizerExampleMobile1-1

Webstart.small2

Click on the screenshot or Launch button above to run this example via Web Start.  Then take a look at the code below, noticing the levels sequence to which the Rectangle widths are bound.  The fact that five rectangles are created is courtesy of the for expression, which evaluates to a sequence of Rectangle instances:

/*
* MobileEqualizerMain.fx
*
* Developed 2009 by James L. Weaver to demonstrate binding in JavaFX
* with UI classes in the JavaFX Mobile profile, and keyboard input.
*/

package projavafx.mobilebinding.ui;

import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.text.*;

var levels: Number[] = [30, 40, 50, 45, 35];
var selectedBarIndex: Integer = 0;
def MAX_LEVEL: Number = 230;
def MIN_LEVEL:Number = 10;
var groupRef: Group;

Stage {
  title: "Binding Example"
  scene: Scene {
    fill: Color.BLACK
    width: 240
    height: 320
    content: [
      Text {
        translateX: 25
        translateY: 20
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: "Binding / KeyEvent 2"
        fill: Color.WHITE
      },
      groupRef = Group {
        content: bind for (level in levels)
          Rectangle {
            x: 0
            y: 60 + (indexof level * 30)
            width: level
            height: 20
            fill: LinearGradient {
              startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
              stops: [ Stop { offset: 0.0 color: Color.LIGHTBLUE },
                   Stop { offset: 1.0 color: Color.DARKBLUE } ]
            }
            opacity: if (indexof level == selectedBarIndex) 1 else 0.7
            onMousePressed: function(me:MouseEvent):Void {
              selectedBarIndex = indexof level;
            }
            onMouseDragged: function(me:MouseEvent):Void {
              if (me.x >= MIN_LEVEL and me.x <= MAX_LEVEL) {
                levels[indexof level] = me.x;
              }
            }
          }
        onKeyPressed: function(ke:KeyEvent):Void {
          if (ke.code == KeyCode.VK_RIGHT and levels[selectedBarIndex] <= MAX_LEVEL - 10) {
            levels[selectedBarIndex] += 10;
          }
          else if (ke.code == KeyCode.VK_LEFT and levels[selectedBarIndex] > MIN_LEVEL + 10) {
            levels[selectedBarIndex] -= 10;
          }
          else if (ke.code == KeyCode.VK_DOWN) {
            selectedBarIndex = (selectedBarIndex + 1) mod sizeof levels;
          }
          else if (ke.code == KeyCode.VK_UP) {
            selectedBarIndex = (sizeof levels + selectedBarIndex - 1) mod sizeof levels;
          }
        }
      },
      Text {
        translateX: 25
        translateY: 220
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: bind "Bar:{selectedBarIndex + 1}, Level: {levels[selectedBarIndex]}"
        fill: Color.WHITE
      }
    ]
  }
}
groupRef.requestFocus();

Most of the UI components currently in JavaFX are Swing components in the Desktop Profile, which don't work on JavaFX Mobile.  The next JavaFX release after the upcoming JavaFX SDK 1.1 version is slated to have lots of UI controls that will be in the Common profile, and will therefore work on JavaFX Mobile.  My crystal ball is still in the repair shop, but I anticipate this release to be available before JavaOne 2009. Also, phones that support JavaFX Mobile are due to arrive by JavaOne 2009.

Please leave a comment if you have any questions.

Regards,
Jim Weaver
JavaFXpert.com

February 08, 2009

Binding and KeyEvent Examples in JavaFX Mobile

Note: Now that JavaFX SDK 1.1 has been released, which includes JavaFX Mobile, this post has been superseded by the post entitled JavaFX 1.1 Mobile Example: Using Binding and Key Events

This post is in response to a Sun article entitled Three Reasons Why Your Next Java ME Mobile Application Should Include JavaFX Mobile.  Reason #3, Data Binding With the Bind Keyword, was presented using an example that won't work on JavaFX Mobile profile.  The author's note was: "Since this application uses the SwingSlider component, it won't work on JavaFX Mobile profile, but it's a good example of how to use the bind keyword."

BindingExampleMobile

The screenshot above is a simple example of binding, running in the JavaFX Mobile emulator, that uses UI capabilities that exist on the JavaFX Mobile platform.  It also demonstrates handling mouse and key events.  A little later in this post I'll expand the example to create a UI that behaves somewhat like graphic equalizer controls. Take a look at the code for this example:

/*
* MobileBindingMain.fx
*
* Developed 2009 by James L. Weaver to demonstrate binding in JavaFX
* with UI classes in the JavaFX Mobile profile, and keyboard input.
*/

package projavafx.mobilebinding.ui;

import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.text.*;

var level:Number = 30;
def MAX_LEVEL:Number = 230;
def MIN_LEVEL:Number = 10;
var rectRef:Rectangle;

Stage {
  title: "Binding Example"
  scene: Scene {
    fill: Color.BLACK
    width: 240
    height: 320
    content: [
      Text {
        translateX: 20
        translateY: 20
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: "Binding / KeyEvent 1"
        fill: Color.WHITE
      },
      rectRef = Rectangle {
        x: 0
        y: 60
        width: bind level
        height: 20
        fill: LinearGradient {
          startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
          stops: [ Stop { offset: 0.0 color: Color.LIGHTBLUE },
               Stop { offset: 1.0 color: Color.DARKBLUE } ]
        }
        onMouseDragged: function(me:MouseEvent):Void {
          if (me.x >= MIN_LEVEL and me.x <= MAX_LEVEL) {
            level = me.x;
          }
        }
        onKeyPressed: function(ke:KeyEvent):Void {
          if (ke.code == KeyCode.VK_RIGHT and level <= MAX_LEVEL - 10) {
            level += 10;
          }
          else if (ke.code == KeyCode.VK_LEFT and level >= MIN_LEVEL + 10) {
            level -= 10;
          }
        }
      },
      Text {
        translateX: 20
        translateY: 100
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: bind "Level: {level}"
        fill: Color.WHITE
      }
    ]
  }
}
rectRef.requestFocus();

The length of the bar can be adjusted by clicking in the bar and dragging the mouse.  It can also be adjusted by pressing the left and right arrow keys, either on the computer keyboard or on the mobile emulator.  As shown in the listing above, the width of the rectangle is bound to the value of the level variable.

The next example uses a sequence of values to which the bars in the graphic equalizer are bound.  Like the previous example, the length of a bar can be controlled by dragging it or pressing the right and left arrow buttons.  In addition, the bar to be adjusted can be selected by pressing the up and down arrow keys, as well as clicking it with the mouse.  Here's a screenshot of the UI running in the JavaFX Mobile emulator:

EqualizerExampleMobile

Take a look at the code below, noticing the levels sequence to which the Rectangle widths are bound.  The fact that five rectangles are created is courtesy of the for expression, which evaluates to a sequence of Rectangle instances:

/*
* MobileEqualizerMain.fx
*
* Developed 2009 by James L. Weaver to demonstrate binding in JavaFX
* with UI classes in the JavaFX Mobile profile, and keyboard input.
*/

package projavafx.mobilebinding.ui;

import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.text.*;

var levels: Number[] = [30, 40, 50, 45, 35];
var selectedBarIndex: Integer = 0;
def MAX_LEVEL: Number = 230;
def MIN_LEVEL:Number = 10;
var groupRef: Group;

Stage {
  title: "Binding Example"
  scene: Scene {
    fill: Color.BLACK
    width: 240
    height: 320
    content: [
      Text {
        translateX: 25
        translateY: 20
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: "Binding / KeyEvent 2"
        fill: Color.WHITE
      },
      groupRef = Group {
        content: bind for (level in levels)
          Rectangle {
            x: 0
            y: 60 + (indexof level * 30)
            width: level
            height: 20
            fill: LinearGradient {
              startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
              stops: [ Stop { offset: 0.0 color: Color.LIGHTBLUE },
                   Stop { offset: 1.0 color: Color.DARKBLUE } ]
            }
            opacity: if (indexof level == selectedBarIndex) 1 else 0.7
            onMousePressed: function(me:MouseEvent):Void {
              selectedBarIndex = indexof level;
            }
            onMouseDragged: function(me:MouseEvent):Void {
              if (me.x >= MIN_LEVEL and me.x <= MAX_LEVEL) {
                levels[indexof level] = me.x;
              }
            }
          }
        onKeyPressed: function(ke:KeyEvent):Void {
          if (ke.code == KeyCode.VK_RIGHT and levels[selectedBarIndex] <= MAX_LEVEL - 10) {
            levels[selectedBarIndex] += 10;
          }
          else if (ke.code == KeyCode.VK_LEFT and levels[selectedBarIndex] > MIN_LEVEL + 10) {
            levels[selectedBarIndex] -= 10;
          }
          else if (ke.code == KeyCode.VK_DOWN) {
            selectedBarIndex = (selectedBarIndex + 1) mod sizeof levels;
          }
          else if (ke.code == KeyCode.VK_UP) {
            selectedBarIndex = (sizeof levels + selectedBarIndex - 1) mod sizeof levels;
          }
        }
      },
      Text {
        translateX: 25
        translateY: 220
        textOrigin: TextOrigin.TOP
        font: Font {
          name: "Sans serif"
          size: 18
        }
        content: bind "Bar:{selectedBarIndex + 1}, Level: {levels[selectedBarIndex]}"
        fill: Color.WHITE
      }
    ]
  }
}
groupRef.requestFocus();

Most of the UI components currently in JavaFX are Swing components in the Desktop Profile, which don't work on JavaFX Mobile.  The next JavaFX release after the upcoming JavaFX SDK 1.1 version is slated to have lots of UI controls that will be in the Common profile, and will therefore work on JavaFX Mobile.  My crystal ball is still in the repair shop, but I anticipate this release to be available before JavaOne 2009.  Also, phones that support JavaFX Mobile are due to arrive by JavaOne 2009.

Please leave a comment if you have any questions.

Regards,
Jim Weaver
JavaFXpert.com

January 22, 2009

JavaFX Mobile Coming in February 2009: A Report from the Sun M3DD Conference

Geeky note: Last year this conference was known as MEDD (Mobile and Embedded Developer Days).  When I saw that it is called M3DD this year, I thought someone was getting cute with l33t, especially given that most texting is done on mobile devices :-)  Turns out, this stands for Mobile, Media and eMbedded Developer Days.

Stephen Chin, co-author of the upcoming Pro JavaFX book, attended the M3DD conference in part to do research on JavaFX Mobile for the book.  Take a look at his blog post, which corroborates that the JavaFX 1.1 release due in February 2009 will include JavaFX Mobile.

M3DD1

Also, be sure to check out Stephen's recent interview with InfoQ that has good information about WidgetFX and JFXtras, two open source JavaFX projects.

Thanks,
Jim Weaver
JavaFXpert.com

December 22, 2008

More Cowbell! An Imaginary Audio Control Example in JavaFX

Stockholm-09-Horizontal

One of my favorite Saturday Night Live sketches is More Cowbell, in which Christopher Walken's character keeps asking for "more cowbell" during a recording session.  Today's example covers some of the simple but powerful concepts of JavaFX in the context of an imaginary iPhone-esque application that lets you select a music genre and control the volume.  Of course, "Cowbell Metal", shortened to "Cowbell", is one of the available genres :-)   Click the screenshot below to launch the application, and then I'll show you the code behind it.

Audio_configuration


Application Behavior and the Code Behind It

When you play with the application, notice that adjusting the volume slider changes the associated decibel (dB) level displayed.  Also, selecting the Muting checkbox disables the slider, and selecting various genres changes the volume slider.  This behavior is enabled by concepts that you'll see in the code below, such as binding to a class that contains a model, on replace triggers, and sequences (think arrays).

Here is the main program, which contains the declarative script that expresses the UI:

/*
* AudioConfigMain.fx - A JavaFX Script example program that demonstrates
* "the way of JavaFX" (binding to model classes, triggers, sequences, and
* declaratively expressed, node-centric UIs).  Note: Because this example
* covers beginning JavaFX concepts, it is more verbose than necessary.
*
* Developed 2008 by James L. Weaver jim.weaver [at] javafxpert.com
* as a JavaFX Script SDK 1.0 example for the Pro JavaFX book.
*/
package projavafx.audioconfig.ui;

import javafx.ext.swing.*;
import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;
import projavafx.audioconfig.model.AudioConfigModel;

Stage {
  var acModel = AudioConfigModel {
    selectedDecibels: 35
  }
  title: "Audio Configuration"
  scene: Scene {
    content: [
      Rectangle {
        x: 0
        y: 0
        width: 320
        height: 45
        fill: LinearGradient {
          startX: 0.0
          startY: 0.0
          endX: 0.0
          endY: 1.0
          stops: [
            Stop {
              color: Color.web("0xAEBBCC")
              offset: 0.0
            },
            Stop {
              color: Color.web("0x6D84A3")
              offset: 1.0
            },
          ]
        }
      },
      Text {
        translateX: 65
        translateY: 12
        textOrigin: TextOrigin.TOP
        fill: Color.WHITE
        content: "Audio Configuration"
        font: Font {
          name: "Arial Bold"
          size: 20
        }
      },
      Rectangle {
        x: 0
        y: 43
        width: 320
        height: 300
        fill: Color.rgb(199, 206, 213)
      },
      Rectangle {
        x: 9
        y: 54
        width: 300
        height: 130
        arcWidth: 20
        arcHeight: 20
        fill: Color.color(1.0, 1.0, 1.0)
        stroke: Color.color(0.66, 0.67, 0.69)
      },
      Text {
        translateX: 18
        translateY: 69
        textOrigin: TextOrigin.TOP
        fill: Color.web("0x131021")
        content: bind "{acModel.selectedDecibels} dB"
        font: Font {
          name: "Arial Bold"
          size: 18
        }
      },
      SwingSlider {
        translateX: 120
        translateY: 69
        width: 175
        enabled: bind not acModel.muting
        minimum: bind acModel.minDecibels
        maximum: bind acModel.maxDecibels
        value: bind acModel.selectedDecibels with inverse
      },
      Line {
        startX: 9
        startY: 97
        endX: 309
        endY: 97
        stroke: Color.color(0.66, 0.67, 0.69)
      },
      Text {
        translateX: 18
        translateY: 113
        textOrigin: TextOrigin.TOP
        fill: Color.web("0x131021")
        content: "Muting"
        font: Font {
          name: "Arial Bold"
          size: 18
        }
      },
      SwingCheckBox {
        translateX: 280
        translateY: 113
        selected: bind acModel.muting with inverse
      },
      Line {
        startX: 9
        startY: 141
        endX: 309
        endY: 141
        stroke: Color.color(0.66, 0.67, 0.69)
      },
      Text {
        translateX: 18
        translateY: 157
        textOrigin: TextOrigin.TOP
        fill: Color.web("0x131021")
        content: "Genre"
        font: Font {
          name: "Arial Bold"
          size: 18
        }
      },
      SwingComboBox {
        translateX: 204
        translateY: 148
        width: 93
        items: bind for (genre in acModel.genres) {
          SwingComboBoxItem {
            text: genre
          }
        }
        selectedIndex: bind acModel.selectedGenreIndex with inverse
      }
    ]
  }
}

Notice how the bind operator is used in various places to cause the UI to reflect the state of the model.  In a couple of places, a bind with inverse is employed to keep the UI and the model class in sync bi-directionally.  Now take a look at the model class, and in particular the on replace trigger that is invoked when the user selects a genre:

/*
* AudioConfigModel.fx - The model class behind a JavaFX Script example
* program that demonstrates "the way of JavaFX" (binding to model classes,
* triggers, sequences, and declaratively expressed, node-centric UIs).
*
* Developed 2008 by James L. Weaver jim.weaver [at] javafxpert.com
* as a JavaFX Script SDK 1.0 example for the Pro JavaFX book.
*/
package projavafx.audioconfig.model;

/**
* The model class that the AudioConfigMain.fx script uses
*/
public class AudioConfigModel {
  /**
   * The minimum audio volume in decibels
   */
  public var minDecibels:Integer = 0;

  /**
   * The maximum audio volume in decibels
   */
  public var maxDecibels:Integer = 160;

  /**
   * The selected audio volume in decibels
   */
  public var selectedDecibels:Integer = 0;

  /**
   * Indicates whether audio is muted
   */
  public var muting:Boolean = false;


  /**
   * List of some musical genres
   */
  public var genres = [
    "Chamber",
    "Country",
    "Cowbell",
    "Metal",
    "Polka",
    "Rock"
  ];

  /**
   * Index of the selected genre
   */
  public var selectedGenreIndex:Integer = 0 on replace {
    if (genres[selectedGenreIndex] == "Chamber") {
      selectedDecibels = 80;
    }
    else if (genres[selectedGenreIndex] == "Country") {
      selectedDecibels = 100;
    }
    else if (genres[selectedGenreIndex] == "Cowbell") {
      selectedDecibels = 150;
    }
    else if (genres[selectedGenreIndex] == "Metal") {
      selectedDecibels = 140;
    }
    else if (genres[selectedGenreIndex] == "Polka") {
      selectedDecibels = 120;
    }
    else if (genres[selectedGenreIndex] == "Rock") {
      selectedDecibels = 130;
    }
  };
}

As always, please leave a comment if you have any questions!

Learn JavaFX in Stockholm, Sweden in January 2009

I'll be speaking on JavaFX at the Jfokus 2009 conference in January.  While in the area, I will also be conducting a two day JavaFX class in Stockholm entitled "Rich Internet Application Development with JavaFX".  I'll be teaching this two day class for Informator beginning January 29, 2009.

Regards,
Jim Weaver
JavaFXpert.com

January 23, 2008

AGUI Aqui? - Java Mobile & Embedded Developer Days

In yesterday's post, I tried to speak French.  The title of today's post is partially in Spanish.  I guess I'm trying to be more global :-) 

After a day of flying, I'm excited about what I'll learn today at the Java Mobile & Embedded Developer Days in Santa Clara, California!  Because there will be lots of mobile developers and speakers here, I'll be interested in gauging how much awareness and momentum has grown around AGUI (Advanced Graphics and User Interface), which is the graphical portion of the JavaFX Mobile stack.

Agui_phone

I'll have much more to say about the conference, and hopefully AGUI, in tomorrow's post.

Regards,
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications

Immediate eBook (PDF) download available at the book's Apress site

December 16, 2007

JavaFX Mobile Addressed in JavaPolis 2007 Keynotes

It's time for this weblog to broach the JavaFX Mobile subject, and this is the perfect opportunity, because it was part of the JavaPolis 2007 keynote sessions on Wednesday and Thursday.  James Gosling addressed JavaFX Mobile in his keynote entitled The State of the Java Universe, and Tim Cramer (Sun's Executive Director of Consumer Solutions) gave a keynote address entitled Java in the Client, in which he spent some of the time talking about JavaFX Mobile.  Here are some of the JavaFX Mobile-related points that they discussed, with the help of Sun Java "Evangelist" Angela Caicedo.

JavaFX Mobile (when available) will support Java Micro Edition (ME) applications.  To illustrate this, I'd like to refer to The Big Picture slide from the Sun Developer Network JavaFX site:

Ig_javafx_architecture

The bottom layer (white wedge) of these stacks are the underlying Java capabilities on the device.  In the case of more powerful mobile devices, as shown above in the column labeled JavaFX Mobile, CDC (Connected Device Configuration) is a Java ME term that specifies the underlying Java framework and capability.  On top of that in the orange JavaFX Framework layer is a set of APIs that provide various services, in this case the AGUI (Advanced Graphics and User Interface) platform, also known as JSR-209.

An API that James Gosling and Tim Cramer both mentioned was the MSA (Mobile Services Architecture) platform, also known as JSR-248.  This runs on the CLDC (Connected Limited Device Configuration) and is meant for less capable phones than ones that have the CDC framework.

The top layer represents the interactive content of an application, written in JavaFX Script, running on the device, and using the services offered by the underlying frameworks.  An unknown at this point is when JavaFX Script (compiled) will be ready to run on each of these configurations (CLDC and CDC).

My company (LAT) is involved in a mobile phone application development project, and will be targeting the CDC.  Our strategy will be to use the UI tools and technologies available today to develop prototypes on the phones, and to simultaneously develop compiled JavaFX Script prototypes on desktop machines.  When JavaFX Script is available for the CDC, then we'll replace the UI code with the JavaFX Script code that we'll have developed by that time.  This brings me to the next point: Java ME development tools available today.

Cool Java ME Development Tools are Available Now

The newly-released NetBeans 6.0 Mobility version available as an option on the NetBeans IDE 6.0 Download page has some very nice mobile application development tools, including the Visual Mobile Designer and the Mobile Game Builder.  Angela demonstrated both of them, but spent more time on the Mobile Game Builder because the Java Evangelist job requires playing with the coolest stuff and having fun.

So, the subject has been broached.  I'll bring you more on JavaFX Mobile as it becomes available.

Regards,
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications
eBook (PDF) download immediately available at the book's Apress site

My Photo

Upcoming Speaking Engagements:


  • Stephen Chin and Jim Weaver speaking about JavaFX Platform

  • Speaking on JavaFX and Java at Øredev in Malmö, Sweden on 2-6 November, 2009

Upcoming JavaFX Training:


  • Developing Secure, Rich Internet Applications Hosted on a Variety of Clients Using JavaFX Technology

Enter your email address:

Delivered by FeedBurner

Available now as early access eBook


  • Click book image above to obtain eBook

Twitter Updates

    follow me on Twitter

    Affiliations:

    DZone Links:


    July 2009

    Sun Mon Tue Wed Thu Fri Sat
          1 2 3 4
    5 6 7 8 9 10 11
    12 13 14 15 16 17 18
    19 20 21 22 23 24 25
    26 27 28 29 30 31  

    Disclaimer:

    • By reading this site, you are agreeing that under no circumstances will Veriana Networks, Inc. or its affiliates be responsible for (1) any information contained on or omitted from the site, (2) any person's reliance on any such information, whether or not the information is correct, current or complete, (3) the consequences of any action you or any other person takes or fails to take, whether or not based on information provided by or as a result of the use of the sites.