« July 2008 | Main | September 2008 »

August 2008

August 26, 2008

Creating Games with JavaFX: Silveira is Having Too Much Fun :-)

I've featured Silveira Neto's JavaFX work (play?) in a couple of recent posts, and it appears that he's had gaming on his mind lately.  Silveira is a CS student, CEJUG member and Sun Campus Ambassador at Federal University of Ceará.

Netoblackdotgame

His latest creation, shown above, is a game in which the player tries to vacuum up the dirty clouds with a sphere-shaped cleaner.  It demonstrates several techniques in JavaFX, such as creating a side-scrolling game, capturing keyboard input, and ascertaining when a graphical object intersects with a pixel in another graphical object.  You can see more information, including the source code and a YouTube video of the game being played, from Silveira's blog post.

In a prior post, Silveira discusses how to create a side-scrolling game in JavaFX, showing the classes that he's building to support it.

Have fun!

Jim Weaver
JavaFXpert.com blog

August 25, 2008

Ask the Experts: JavaFX Preview Transcripts

As I announced in the TableNode: Creating a Custom Scrollable Table Component in JavaFX post, there is (now was) an Ask the Experts: JavaFX Preview, on August 18-22, 2008.  Several developers took advantage of this opportunity to pose questions to Joshua Marinacci, Martin Brehovsky, and Lawrence McDonough of the JavaFX engineering team.

Asktheexpertsjavafx

Take a look at the transcript if you'd like to learn more about the JavaFX SDK Preview from their answers.  Please leave a comment if you missed this opportunity to ask questions, and I'll try to answer your questions or redirect them to people who can.

Regards,

Jim Weaver
JavaFXpert.com

August 20, 2008

Danny Coward: These are a Few of My Favorite [JavaFX SDK Preview] Things

Many of you know that Danny Coward is the Chief Architect of Sun's Client Software (Java SE, Java ME and JavaFX).  In his August 19, 2008 blog post, Danny stops just short of breaking out into a Rogers and Hammerstein song while reciting some of his favorite things about the JavaFX SDK Preview.

200pxsoundofmusic_soundtrack

Enjoy!

Jim Weaver
JavaFXpert.com

August 17, 2008

TableNode: Creating a Custom Scrollable Table in JavaFX

Stockholm-09-Horizontal

In July 2008 I started the JFX Custom Nodes category that contains a growing series of posts in which a graphics designer (Mark Dingman of Malden Labs) and I are collaborating on an imaginary Sound Beans application.  The objectives of building this application are to demonstrate how to create JavaFX custom nodes, and to provide a case study in how a graphics designer and an application developer can work together effectively in developing JavaFX applications. 

The first post in this series, Rolling Your Own JavaFX "Custom Nodes": A Graphical Menu Example, shows you how to create your own UI controls in JavaFX.  In that post we defined the MenuNode and ButtonNode custom nodes so that you can easily create menus that consist of buttons that fade-in and expand when the mouse rolls over them.  Subsequent posts in this series have:

  • defined a DeckNode that stores a set of Node instances and displays one of these nodes at a time.
  • defined a ProgressNode control that may be use to show the progress of an operation.  That post also introduced a long overdue model class into the Sound Beans application.

In today's post, we're going to build a custom node name TableNode whose purpose is to provide a scrollable table whose rows can be viewed and selected.  Each cell in the table can hold a subclass of Node, so it is in line with the node-centric approach that the JavaFX SDK 1.0 will take.  By the way, I do expect that the JavaFX SDK 1.0 will have some sort of table UI control.  Anyway, here a screenshot of the TableNode being used in our imaginary Sound Beans program:

Tablenodeexample


This is based upon the playlist comp (mock-up) that Mark Dingman gave me, shown in the Getting Decked: Another JavaFX Custom Node post.  I subsequently asked him for a comp of a scrollbar that I could implement by drawing shapes (as opposed to using images).  Mark's comp included the rounded rectangle for the proportional scrollbar thumb shown above, with the scrollbar's track having a slight horizontal gradient.

In this iteration of our imaginary Sound Beans program, the number in the upper left hand corner of the UI will change as you click different rows in the table, demonstrating that you can bind to the selectedIndex attribute of the TableNode.  In future iterations we'll cause the album graphics, title, etc. to change, and we'll dispense of that number in the upper left corner.  Anyway, try it out by clicking on this Java Web Start link, keeping in mind that you'll need at least JRE 6.  Also, installing Java SE 6 update 10 will give you faster deployment time.

Webstartsmall2

Here's the code for the TableNode custom node, in a file named TableNode.fx:

/*
*  TableNode.fx -
*  A custom node that contains rows and columns, each cell
*  containing a node.
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to demonstrate how to create custom nodes in JavaFX
*/

package com.javafxpert.custom_node;

import javafx.input.*;
import javafx.scene.*;
import javafx.scene.geometry.*;
import javafx.scene.paint.*;
import javafx.scene.transform.*;
import java.lang.System;

/*
* A custom node that contains rows and columns, each cell
* containing a node.  Column widths may be set individually,
* and the height of the rows can be set.  In addition, several
* other attributes such as width and color of the scrollbar
* may be set.  The scrollbar will show only when necessary,
* and overlays the right side of each row, so the rightmost
* column should be given plenty of room to display data and
* a scrollbar.
*/
public class TableNode extends CustomNode {

  /*
   * Contains the height of the table in pixels.
   */
  public attribute height:Integer = 200;
   
  /*
   * Contains the height of each row in pixels.
   */
  public attribute rowHeight:Integer;
   
  /*
   * A sequence containing the column widths in pixels.  The
   * number of elements in the sequence determines the number of
   * columns in the table.
   */
  public attribute columnWidths:Integer[];
   
  /*
   * A sequence containing the nodes in the cells.  The nodes are
   * placed from left to right, continuing to the next row when
   * the current row is filled.
   */
  public attribute content:Node[];
   
  /*
   * The selected row number (zero-based)
   */
  public attribute selectedIndex:Integer;
   
  /*
   * The height (in pixels) of the space between rows of the table.
   * This space will be filled with the tableFill color.
   */
  public attribute rowSpacing:Integer = 1;
   
  /*
   * The background color of the table
   */
  public attribute tableFill:Paint;
   
  /*
   * The background color of an unselected row
   */
  public attribute rowFill:Paint;
   
  /*
   * The background color of a selected row
   */
  public attribute selectedRowFill:Paint;
   
  /*
   * The color or gradient of the vertical scrollbar.
   */
  public attribute vertScrollbarFill:Paint = Color.BLACK;
   
  /*
   * The color or gradient of the vertical scrollbar thumb.
   */
  public attribute vertScrollbarThumbFill:Paint = Color.WHITE;
   
  /*
   * The width (in pixels) of the vertical scrollbar.
   */
  public attribute vertScrollbarWidth:Integer = 20;
   
  /*
   * The number of pixels from the left of a cell to place the node
   */
  private attribute cellHorizMargin:Integer = 10;
   
  /*
   * Contains the width of the table in pixels.  This is currently a
   * calculated value based upon the specified column widths
   */
  private attribute width:Integer = bind
    computePosition(columnWidths, sizeof columnWidths);
   
  private function computePosition(sizes:Integer[], element:Integer) {
    var position = 0;
    if (sizeof sizes > 1) {
      for (i in [0..element - 1]) {
        position += sizes[i];
      }
    }
    return position;
  }
 
  /**
   * The onSelectionChange function attribute that is executed when the
   * a row is selected
   */
  public attribute onSelectionChange:function(row:Integer):Void;
   
  /**
   * Create the Node
   */
  public function create():Node {
    var numRows = sizeof content / sizeof columnWidths;
    var tableContentsNode:Group;
    var needScrollbar:Boolean = bind (rowHeight + rowSpacing) * numRows  > height;
    Group {
      var thumbStartY = 0.0;
      var thumbEndY = 0.0;
      var thumb:Rectangle;
      var track:Rectangle;
      var rowRef:Group;
      content: [
        for (row in [0..numRows - 1], colWidth in columnWidths) {
          Group {
            transform: bind
              Translate.translate(computePosition(columnWidths, indexof colWidth) +
                                  cellHorizMargin,
                                  ((rowHeight + rowSpacing) * row) + (-1.0 * thumbEndY *
                                  ((rowHeight + rowSpacing) * numRows) / height))
            content: bind [
              Rectangle {
                width: colWidth
                height: rowHeight
                fill: if (indexof row == selectedIndex)
                        selectedRowFill
                      else
                        rowFill
              },
              Line {
                startX: 0
                startY: 0
                endX: colWidth
                endY: 0
                strokeWidth: rowSpacing
                stroke: tableFill
              },
              rowRef = Group {
                var node =
                  content[indexof row * (sizeof columnWidths) + indexof colWidth];
                transform: bind Translate.translate(0, rowHeight / 2 -
                                                       node.getHeight() / 2)
                content: node
              }
            ]
            onMouseClicked:
              function (me:MouseEvent) {
                selectedIndex = row;
                onSelectionChange(row);
              }
          }
        },
        // Scrollbar
        if (needScrollbar)
          Group {
            transform: bind Translate.translate(width - vertScrollbarWidth, 0)
            content: [
              track = Rectangle {
                x: 0
                y: 0
                width: vertScrollbarWidth
                height: bind height
                fill: vertScrollbarFill
              },
              //Scrollbar thumb
              thumb = Rectangle {
                x: 0
                y: bind thumbEndY
                width: vertScrollbarWidth
                height: bind 1.0 * height / ((rowHeight + rowSpacing) * numRows) * height
                fill: vertScrollbarThumbFill
                arcHeight: 10
                arcWidth: 10
                onMousePressed: function(e:MouseEvent):Void { 
                  thumbStartY = e.getDragY() - thumbEndY; 
                } 
                onMouseDragged: function(e:MouseEvent):Void {
                  var tempY = e.getDragY() - thumbStartY;
                  // Keep the scroll thumb within the bounds of the scrollbar
                  if (tempY >=0 and tempY + thumb.getHeight() <= track.getHeight()) {
                    thumbEndY = tempY; 
                  }
                  else if (tempY < 0) {
                    thumbEndY = 0;
                  }
                  else {
                    thumbEndY = track.getHeight() - thumb.getHeight();
                  }
                }
                onMouseDragged: function(e:MouseEvent):Void {
                  var tempY = e.getDragY() - thumbStartY;
                  // Keep the scroll thumb within the bounds of the scrollbar
                  if (tempY >=0 and tempY + thumb.getHeight() <= track.getHeight()) {
                    thumbEndY = tempY; 
                  }
                  else if (tempY < 0) {
                    thumbEndY = 0;
                  }
                  else {
                    thumbEndY = track.getHeight() - thumb.getHeight();
                  }
                }
              }
            ]
          } 
        else
          null
      ]
      clip:
        Rectangle {
          width: bind width
          height: bind height
        }
      onMouseWheelMoved: function(e:MouseEvent):Void {
        var tempY = thumbEndY + e.getWheelRotation() * 4;
        // Keep the scroll thumb within the bounds of the scrollbar
        if (tempY >=0 and tempY + thumb.getHeight() <= track.getHeight()) {
          thumbEndY = tempY; 
        }
        else if (tempY < 0) {
          thumbEndY = 0;
        }
        else {
          thumbEndY = track.getHeight() - thumb.getHeight();
        }
      }
    }   
  }

As you can see by the public attributes, there are several TableNode attributes that may be configured by the developer, including the height of the table, the height of the rows, the width of each individual column, and the colors or gradients of various UI elements.  Notice that the code at the end of the listing provides mouse wheel support.  Now take a look at the main program, particularly the section denoted by The "Play" page comment where the TableNode instance is being created, in a file named TableNodeExampleMain.fx:

/*
*  TableNodeExampleMain.fx -
*  An example of using the TableNode custom node.  It also demonstrates
*  the ProgressNode, DeckNode, MenuNode and ButtonNode custom nodes
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to demonstrate how to create custom nodes in JavaFX
*/
package com.javafxpert.table_node_example.ui;

import javafx.application.*;
import javafx.ext.swing.*;
import javafx.scene.*;
import javafx.scene.geometry.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;
import java.lang.Object;
import java.lang.System;
import com.javafxpert.custom_node.*;
import com.javafxpert.table_node_example.model.*;

var deckRef:DeckNode;

Frame {
  var model = TableNodeExampleModel.getInstance();
  var stageRef:Stage;
  var menuRef:MenuNode;
  title: "TableNode Example"
  width: 500
  height: 400
  visible: true
  stage:
    stageRef = Stage {
      fill: Color.BLACK
      content: [
        deckRef = DeckNode {
          fadeInDur: 700ms
          content: [
            // The "Splash" page
            Group {
              var vboxRef:VBox;
              var splashFont =
                Font {
                  name: "Sans serif"
                  style: FontStyle.BOLD
                  size: 12
                };
              id: "Splash"
              content: [
                ImageView {
                  image:
                    Image {
                      url: "{__DIR__}images/splashpage.png"
                    }
                },
                vboxRef = VBox {
                  translateX: bind stageRef.width - vboxRef.getWidth() - 10
                  translateY: 215
                  spacing: 1
                  content: [
                    Text {
                      content: "A Fictitious Audio Application that Demonstrates"
                      fill: Color.WHITE
                      font: splashFont
                    },
                    Text {
                      content: "Creating JavaFX Custom Nodes"
                      fill: Color.WHITE
                      font: splashFont
                    },
                    Text {
                      content: "Application Developer: Jim Weaver"
                      fill: Color.WHITE
                      font: splashFont
                    },
                    Text {
                      content: "Graphics Designer: Mark Dingman"
                      fill: Color.WHITE
                      font: splashFont
                    },
                  ]
                }
              ]
            },
            // The "Play" page
            VBox {
              var tableNode:TableNode
              id: "Play"
              spacing: 4
              content: [
                Group {
                  content: [
                    ImageView {
                      image:
                        Image {
                          url: "{__DIR__}images/playing_currently.png"
                        }
                    },
                    Text {
                      textOrigin: TextOrigin.TOP
                      content: bind "{tableNode.selectedIndex}"
                      font: Font {
                        size: 24
                      }
                    }
                  ]
                },
                tableNode = TableNode {
                  height: 135
                  rowHeight: 25
                  rowSpacing: 2
                  columnWidths: [150, 247, 25, 70]
                  tableFill: Color.BLACK
                  rowFill: Color.#1c1c1c
                  selectedRowFill: Color.#2d2d2d
                  selectedIndex: -1
                  vertScrollbarWidth: 20
                  vertScrollbarFill: LinearGradient {
                    startX: 0.0
                    startY: 0.0
                    endX: 1.0
                    endY: 0.0
                    stops: [
                      Stop {
                        offset: 0.0
                        color: Color.#0b0b0b
                      },
                      Stop {
                        offset: 1.0
                        color: Color.#343434
                      }
                    ]
                  }
                  vertScrollbarThumbFill: Color.#efefef
                  content: bind
                    for (obj in model.playlistObjects) {
                      if (obj instanceof String)
                        Text {
                          textOrigin: TextOrigin.TOP
                          fill: Color.#b7b7b7
                          content: obj as String
                          font:
                            Font {
                              size: 11
                            }
                        }
                      else if (obj instanceof Image)
                        ImageView {
                          image: obj as Image
                        }
                      else
                        null
                    }
                  onSelectionChange:
                    function(row:Integer):Void {
                      System.out.println("Table row #{row} selected");
                    }
                }
              ]
            },
            // The "Burn" page
            Group {
              var vboxRef:VBox;
              id: "Burn"
              content: [
                vboxRef = VBox {
                  translateX: bind stageRef.width / 2 - vboxRef.getWidth() / 2
                  translateY: bind stageRef.height / 2 - vboxRef.getHeight() / 2
                  spacing: 15
                  content: [
                    Text {
                      textOrigin: TextOrigin.TOP
                      content: "Burning custom playlist to CD..."
                      font:
                        Font {
                          name: "Sans serif"
                          style: FontStyle.PLAIN
                          size: 22
                        }
                      fill: Color.#d3d3d3
                    },
                    ProgressNode {
                      width: 430
                      height: 15
                      progressPercentColor: Color.#bfdfef
                      progressTextColor: Color.#0c1515
                      progressText: bind "{model.remainingBurnTime} Remaining"
                      progressFill:
                        LinearGradient {
                          startX: 0.0
                          startY: 0.0
                          endX: 0.0
                          endY: 1.0
                          stops: [
                            Stop {
                              offset: 0.0
                              color: Color.#00c0ff
                            },
                            Stop {
                              offset: 0.20
                              color: Color.#00acea
                            },
                            Stop {
                              offset: 1.0
                              color: Color.#0070ae
                            },
                          ]
                        }
                      barFill:
                        LinearGradient {
                          startX: 0.0
                          startY: 0.0
                          endX: 0.0
                          endY: 1.0
                          stops: [
                            Stop {
                              offset: 0.0
                              color: Color.#707070
                            },
                            Stop {
                              offset: 1.0
                              color: Color.#585858
                            },
                          ]
                        }
                      progress: bind model.burnProgressPercent / 100.0
                    },
                    ComponentView {
                      component:
                        FlowPanel {
                          background: Color.BLACK
                          content: [
                            Label {
                              text: "Slide to simulate burn progress:"
                              foreground: Color.#d3d3d3
                            },
                            Slider {
                              orientation: Orientation.HORIZONTAL
                              minimum: 0
                              maximum: 100
                              value: bind model.burnProgressPercent with inverse
                              preferredSize: [200, 20]
                            }
                          ]
                        }
                    }
                  ]
                }
              ]
            },
            // The "Config" page
            Group {
              id: "Config"
              content: [
                ImageView {
                  image:
                    Image {
                      url: "{__DIR__}images/config.png"
                    }
                }
              ]
            },
            // The "Help" page
            Group {
              id: "Help"
              content: [
                ImageView {
                  image:
                    Image {
                      url: "{__DIR__}images/help.png"
                    }
                }
              ]
            }
          ]
        },
        menuRef = MenuNode {
          translateX: bind stageRef.width / 2 - menuRef.getWidth() / 2
          translateY: bind stageRef.height - menuRef.getHeight()
          buttons: [
            ButtonNode {
              title: "Play"
              imageURL: "{__DIR__}icons/play.png"
              action:
                function():Void {
                  deckRef.visibleNodeId = "Play";
                }
            },
            ButtonNode {
              title: "Burn"
              imageURL: "{__DIR__}icons/burn.png"
              action:
                function():Void {
                  deckRef.visibleNodeId = "Burn";
                }
            },
            ButtonNode {
              title: "Config"
              imageURL: "{__DIR__}icons/config.png"
              action:
                function():Void {
                  deckRef.visibleNodeId = "Config";
                }
            },
            ButtonNode {
              title: "Help"
              imageURL: "{__DIR__}icons/help.png"
              action:
                function():Void {
                  deckRef.visibleNodeId = "Help";
                }
            },
          ]
        }
      ]
    }
}

deckRef.visibleNodeId = "Splash";

The Model Behind the UI

Since the "way of JavaFX" is to bind UI attributes to a model, the content attribute of the TableNode is bound to the model as shown above.  Shown below is the model for the Sound Beans program so far, in a file named TableNodeExampleModel.fx.  Notice that the playlistObjects sequence can contain any kind of object, and that we're specifically avoiding putting Node instances in the model (as those belong in the UI).  To populate the TableNode, therefore, I'm taking the approach of having the model contain strings such as album titles and the URL of an image.  During the bind to the content attribute of the TableModel shown above, the Node subclasses (e.g. Text and ImageView) are created.

/*
*  TableNodeExampleModel.fx -
*  The model behind the TableNode example
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*/
package com.javafxpert.table_node_example.model;

import java.lang.Object;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.text.*;

/**
* The model behind the TableNode example
*/
public class TableNodeExampleModel {
 
  /**
   * The total estimated number of seconds for the burn.
   * For this example program, we'll set it to 10 minutes
   */
  public attribute estimatedBurnTime:Integer = 600;

  /**
   * The percent progress of the CD burn, represented by a number
   * between 0 and 100 inclusive.
   */
  public attribute burnProgressPercent:Integer on replace {
      var remainingSeconds = estimatedBurnTime * (burnProgressPercent / 100.0) as Integer;
      remainingBurnTime = "{remainingSeconds / 60}:{%02d (remainingSeconds mod 60)}";
  };

  /**
   * The time remaining on the CD burn, expressed as a String in mm:ss
   */
  public attribute remainingBurnTime:String;

  /**
   * An image of a play button to be displayed in each row of the table
   */
  private attribute playBtnImage = Image {url: "{__DIR__}images/play-btn.png"};
   
  /**
   * The song information in the playlist
   */
  public attribute playlistObjects:Object[] =
    ["Who'll Stop the Rain", "Three Sides Now", playBtnImage, "2:43",
     "Jackie Blue", "Ozark Mountain Devils", playBtnImage, "2:15",
     "Come and Get Your Love", "Redbone", playBtnImage, "3:22",
     "Love Machine", "Miracles", playBtnImage, "2:56",
     "25 or 6 to 4", "Chicago", playBtnImage, "3:02",
     "Free Bird", "Lynard Skynard", playBtnImage, "5:00",
     "Riding the Storm Out", "REO Speedwagon", playBtnImage, "3:00",
     "Lay it on the Line", "Triumph", playBtnImage, "2:00",
     "Secret World", "Peter Gabriel", playBtnImage, "4:00"];
 
 
 
  //-----------------Use Singleton pattern to get model instance -----------------------
  private static attribute instance:TableNodeExampleModel;

  public static function getInstance():TableNodeExampleModel {
    if (instance == null) {
      instance = TableNodeExampleModel {};
    }
    else {
      instance;
    }
  }
}

As always, if you have any questions or input, please leave a comment.  By the way, the images for this article can be downloaded so that you can build and run this example with the graphics. This is a zip file that you can expand in the project's classpath.  You will need the ButtonNode, MenuNode, DeckNode and ProgressNode code from previous posts in this JFX Custom Nodes series.


Got JavaFX Questions?

Well, you're in luck!  There will be an Ask the Experts: JavaFX Preview, on August 18-22, 2008.
You can post your questions during this session and get answers from key members of Sun's JavaFX engineering team.

Regards,
Jim Weaver
JavaFXpert.com

August 13, 2008

Simon Says: Read this JavaFX Book as it's Being Written

Morris_cover150
Simon Morris is writing a JavaFX book with Manning Publications Co. entitled JavaFX in Action.  It is a "MEAP" release, which stands for Manning Early Access Program.  In that program you get to read the eBook chapters as the author is writing them, and provide input on the author forum.

Here is the table of contents from the book's site on August 12, 2008:

  1. Welcome to the future: introducing JavaFX - FREE
  2. JavaFX script part 1: Data - AVAILABLE
  3. JavaFX UI: The quickest GUI you've ever coded
  4. Painting pictures: impressive graphics, modest code
  5. Hex, files, and video tape: getting serious with GUI fun
  6. Is there anyone out there: connecting to a Web Service
  7. Going back to the Web: from application to applet
  8. Going mobile: escaping the desktop
  9. The best of both worlds: mixing JavaFX and Java

Simon book is based on the latest version of JavaFX, which is the SDK Preview, available at Sun's JavaFX website.  Simon says: Go get the JavaFX SDK Preview release, and follow along as he writes the book :-)

Congratulations Simon!
Jim Weaver
JavaFXpert.com

August 11, 2008

Dragging Graphical Nodes in JavaFX: Examples by Silveira

Featured at the finale of the I Hear Voices: Post JavaFX SDK Preview Release post, Silveira Neto is a CS student, CEJUG member and Sun Campus Ambassador at Federal University of Ceará.  Silveira has been working on some fun examples of dragging, rotating, and animating JavaFX graphical nodes, showing you both the code and YouTube videos of them in action.  Check them out!

Silveiradrag1

Got JavaFX Questions?

Well, you're in luck!  There will be an Ask the Experts: JavaFX Preview, on August 18-22, 2008.
You can post your questions during this session and get answers from key members of Sun's JavaFX engineering team.

Regards,
Jim Weaver

August 06, 2008

Using the JavaFX Preview SDK on Linux - Thanks Weiqi Gao!

The I Hear Voices: Post JavaFX SDK Preview Release post highlighted some positive feedback from the developer community.  The same post on JavaLobby was met with responses that made it clear that several developers in the Linux community are frustrated by the fact that only Windows and Mac are officially supported by this technical preview release.

I asked Mike Gionfriddo (JavaFX Architect at Sun) to join the fray during some questions about Linux support in a previous post, and he posted this comment, repeated here for your convenience:

"Jim/Kevin -

From the JavaFX perspective, when we talk about cross platform, its simply not across desktop platforms, but across a range of consumer platforms including mobile and television devices.  As we discussed at JavaOne, we are actively developing both a desktop and mobile release.

Now what's up with Linux? The JavaFX preview release will only be supported on Windows and Mac OS-X.  These two platforms are widely used for the designer/scripter community JavaFX is attempting to reach and we wanted to get feedback from that audience as quickly as possible.  We do plan on supporting Linux in future releases and as Jim points out, you are able to run with the technology preview branch, but Caveat Emptor.

Best Regards,
Mike"

As a result of the question about whether the JavaFX Preview SDK will run on Linux, Weiqi Gao posted an article on his blog entitled "Watch JavaFX SDK Run---On Linux". 

Javafxsdkrunningonlinux

In this article he explains the steps that he took in successfully obtaining, installing, and using the JavaFX Preview SDK on Linux.  Go there and check it out!

Thanks Weiqi!
Jim Weaver

August 02, 2008

I Hear Voices: Post JavaFX SDK Preview Release

I like the way that GeekyCoder, a Java Developer In Singapore, put it in a blog post entitled JavaFX Preview SDK Finally Released:

Geekycodercroppedlogoheader

"Many developers lament why the need for another language and why not improve Swing, the GUI toolkit library?  Well, RIA markets are now evolved to appeal to designers and not only to developers through creating a declarative language that much easier to learn and use while still allow flexibility and power through the core programmatic language. For example, Flex used MXML based on XML as a foundation to build UI with strong data binding capability and ActionScript for programming. Similarly, JavaFX uses JavaFX Script to create UI and Java to extend the application further. Why switch to JavaFX when competitors are already have version of products ahead of JavaFX?  Among the major reasons are existing Java developers can leverage on myriad existing Java open source libraries, existing investment and develop JavaFX application using state of art and powerful IDE like NetBeans, Eclipse and Intellij. Beside, another outstanding  component of JavaFX technology aka JavaFX Mobile, will give a boost in creating rich and powerful mobile application by having almost a full-blown Java SDK built into the phone compare to the limited environment of J2ME. The greatest advantage is that the same desktop application built with JavaFX can be used in the JavaFX-based mobile phone without changing the code base."

The JavaFX SDK Technology Preview Release has given mainstream developers the opportunity to see the capability and potential of JavaFX.  As one that has been enamoured with JavaFX for quite some time, I have been very pleased with the overall reaction from the developer community.

I'd like to congratulate Sun for achieving this milestone, and for their tenacity in continuing to move JavaFX forward.  Here is an interview with Param Singh (senior director of Java marketing at Sun), and Thom Theriault (CTO of MaldenLabs).  In it, Param stated the following:

"Each platform has a core strength. Our strength comes from the ubiquity of the Java runtime, in the mobile area where we are pervasive, and in the six million Java developers who can extend their capabilities to provide Web resident apps and can do it in a faster time frame."

In that interview, Thom had this to say:

"We initially thought Flash/Flex would be easier to start with, but in the end it was harder to do certain functions.  JavaFX gives us the advantage of tying into those tried and true Java APIs that are vital to our app. So while the tools are lacking, they are going to be there."

Also, Nandini Ramani (Director of Engineering for the JavaFX Platform at Sun) did a video interview and demo of the JavaFX Preview SDK with Michael Coté of RedMonk that you'll want to check out.

Because I place most stock in developer voices, I opened this post with a quote from a developer, and I'll close it with a JavaFX code example  that creates sphere with a shadow from Silveira Neto.  Silveira Neto is a Computer Science student and Sun Campus Ambassador at Federal University of Ceará.

Spherewithshadow

Regards, and have fun with the JavaFX Preview SDK!

Jim Weaver

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.