The Java Tutorials' Weblog

pageicon Thursday Apr 02, 2009

Deployment Toolkit 101

The Deployment Toolkit is a set of JavaScript functions that can help developers easily deploy rich internet applications. [Read More]
pageicon Wednesday Apr 01, 2009

Converting Pre-JDK7 File I/O Code

Prior to JDK7, the java.io.File class was the mechanism used for file I/O, but it had several drawbacks. Perhaps you have legacy code that uses java.io.File and would like to take advantage of the java.nio.file.Path functionality with minimal impact on your code.[Read More]
pageicon Tuesday Mar 31, 2009

Deploying An Applet In Under 10 Minutes

Want to learn how to quickly deploy a Java applet?[Read More]
pageicon Friday Mar 27, 2009

PathMatcher in NIO.2

In my last blog entry I show how to walk a file tree using a FileVisitor in a very simple Find example. Alan Bateman (the NIO.2 czar) suggested that, rather than use java.lang.String to match the file, I use the new PathMatcher API. [Read More]
pageicon Tuesday Mar 24, 2009

Traversing a file tree in NIO.2

Have you downloaded JDK7 and played with NIO.2 yet? NIO.2 offers many new I/O features, particularly in the area of files and file system APIs. [Read More]
pageicon Wednesday Feb 04, 2009

JavaBat -- Java Practice Programs

Wow, a very cool website was just brought to my attention. Nick Parlante, of Stanford, has pulled together a website where you can hone your Java skills.

Created with the theory that you learn by doing and the more you do it, the better you get, JavaBat provides a set of programming examples that give you immediate feedback. You can work through several examples in an hour — it compiles and runs your code using a variety of parameters so you can see where it fails. At the end, you can hop over to the "done" page and view your stats. Want to test your skills in a friendly, good-natured competition? Here ya go. :)

JavaBat is one of the neatest, free Java resources I've seen in a long time!

-- Sharon Zakhour

pageicon Monday Feb 02, 2009

NIO and JDK7

You may be familiar with the NIO (New I/O) api. This API, introduced in release 1.4, extended the previous I/O package and included support for pattern matching with Regular Expressions, Buffer support for primitive types, Character-set encoders and decoders, and Channels — an abstraction for devices capable of performing I/O operations (to name just some of the functionality).

You may be familiar with NIO, but have you heard of NIO.2? NIO.2, part of the JDK7 effort, completes some of the work begun in the NIO api and goes much further: It includes an improved filesystem interface, multicast support, asynchronous I/O support, and complete socket-channel functionality (which was begun in release 1.4).

Thanks to OpenJDK, you can download and play with NIO.2 now. The NIO Project Page contains links to the latest binaries, javadoc, JSR 203, and links to bloggers involved in this effort.

-- Sharon Zakhour

pageicon Thursday Jan 15, 2009

Inverse Kinematics Demo

Sun engineer Michael Heinrichs recently wrote a great animation demo that uses inverse kinematics to animate JavaFX objects. Check it out on his blog and feel free to leave a comment!

-- Scott Hommel

pageicon Tuesday Jan 06, 2009

JavaFX Rated as Top 10 for 2008

As you know, JavaFX 1.0 was released in early December and has been receiving some exciting attention among developers and the press. For example, eweek has ranked JavaFX as number 5 in its Top 10 Application Development Products for 2008.

If you haven't yet checked it out, I would refer you to the last several entries on this blog. :)

Also, if you would like to run JavaFX applications and applets while not connected to the internet, check out this article by Thomas Ng.

Happy 2009!!

-- Sharon Zakhour

pageicon Friday Dec 12, 2008

JavaFX Coffee Cup

So the JavaFX™ SDK 1.0 has shipped. I thought that now would be a fun time to try out some of its graphics capabilities. I know that its graphics are really slick... but how easy are they to program? Do you need to be a graphics expert to figure it all out, or can anyone just pick it up and learn?

As for my background, I'm a technical writer and general-purpose computer programmer. I am not a software engineer, graphic designer, or GUI expert. Because of that I'm probably the ideal person to test drive the usability of GUI coding with the SDK. The challenge to myself was to take a single afternoon and code up something "impressive"; it didn't matter what, I just wanted it to have a 3D feel with modern visual/lighting effects like what I see in the SDK demos.

So the first thing I did was to read the GUI tutorial, which quickly brought me up to speed on the basics. (Those completely new to the JavaFX Script programming language will want to first read the core tutorial as well.) I then went to the web, looking for information on drawing 3D shapes in general.

I came across this article, which builds a 3D coffee cup using a freeware vector graphics drawing program called inkscape. Having a limited GUI background, this was exactly the kind of breakdown that I needed. It explained how to make "3D" looking objects from basic 2D shapes, filled in with various color gradients. The challenge to myself was to basically "port" their tool instructions to equivalent calls in the API. By the end of the afternoon, I'd made this cool looking cup:

Here's how I did it...

Making the Frame

Setting up the basic application frame was super easy to do. JavaFX technology lets you "group" multiple objects together, so I made one group for the plate, and another for the cup. These two groups will contain the graphical objects to be rendered on screen:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;

def plateGroup = Group {
     // The group of objects forming the "plate" will go here
}

def cupGroup = Group {
    // The group of objects forming the "cup" will go here
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

There's nothing to display yet, but the code is organized, and that's an important first step. I've used the def keyword to assign these groups to individual variables; this makes it easier to "unplug" a finished group (i.e. the plate) to work on the other (the cup) in isolation, if need be.

Making the Plate

The first step in making the plate was to draw an Ellipse, filled with a RadialGradient that spans three colors (Color.WHITESMOKE, Color.LIGHTGRAY, and Color.DARKGREY):

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

     translateX: 250
     translateY: 300

     content: [
          Ellipse {centerX: 0 centerY: 0  radiusX: 170 radiusY: 50
               fill: RadialGradient{
                         centerX: 0.5 centerY: 0.75
                         stops: [Stop {offset: 0.0 color: Color.WHITESMOKE},
                                 Stop {offset: 0.5 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.DARKGRAY}]
               } 
          } 
     ] 
}

def cupGroup = Group {
    // The group of objects forming the "cup" will go here
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

The translateX and translateY variables of the Group object proved useful for moving the entire group around on screen. I found that getting the exact values for the gradient was just a matter of trial and error. There are a number of different settings that all looked good; finding something that looked "right" was just a matter of plugging in different values and recompiling the program.

Next I added a dark gray ellipse below the plate, and another thin ellipse to make the lip (giving it a 3D feel):

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [ 

          // The gray ellipse under the plate
          Ellipse{centerX: 0 centerY: 10 radiusX: 160 radiusY: 50 fill: Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX: 0 centerY: 3  radiusX: 170 radiusY: 50 fill: Color.LAVENDER}, 

          // The large plate ellipse
          Ellipse{centerX: 0 centerY: 0  radiusX: 170 radiusY: 50
          fill: RadialGradient{
                    centerX: 0.5 centerY: 0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          }
     ]
}

def cupGroup = Group {
    // The group of objects forming the "cup" will go here
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

Since GUI objects are rendered in the order they appear in the source code, I put the main plate ellipse last so that it would cover the tops of all the others. Again, finding the exact values was just a matter of experimentation.

Finally, I recessed the center of the plate:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          },

         // Recessed plate center
           Ellipse{centerX: 0 centerY: 5 radiusX: 90 radiusY: 22
                fill: RadialGradient{
                          centerX: 0.5 centerY: 0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ]
}

def cupGroup = Group {
    // The group of objects forming the "cup" will go here
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

Without this dark shadow, the cup bottom would be hard to see when it's finally in place. In the end this darkened area will be more subtle because the cup will be hiding most of it.

Making the Cup

To make the cup, I just started with a Circle, giving it the the same kind of gradient as used in the plate. My approach here was to treat the cup like a blob of clay. The API contains powerful built-in transforms that I can later use to "stretch" the cup into shape. How cool is that?

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          },

         // Recessed plate center
           Ellipse{centerX: 0 centerY: 5 radiusX: 90 radiusY: 22
                fill: RadialGradient{
                          centerX: 0.5 centerY: 0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ]
}

def cupGroup = Group {

     translateX: 152
     translateY: 20

     content: [
               // Cup body
               Circle {centerX: 100  centerY: 100 radius: 50
                    fill: RadialGradient {
                               centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY: .65, proportional:true
                               stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                       Stop {offset: 1.0 color: Color.SILVER}]
               }
          }
     ]
}


Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

To make this ball more "cup-like", I next placed a white rectangle over the top of the circle to flatten it out:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          },

         // Recessed plate center
           Ellipse{centerX: 0 centerY: 5 radiusX: 90 radiusY: 22
                fill: RadialGradient{
                          centerX: 0.5 centerY: 0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ]
}

def cupGroup = Group {

     translateX: 152
     translateY: 20

     content: [
               // Cup body
               Circle {centerX: 100  centerY: 100 radius: 50
                    fill: RadialGradient {
                               centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY: .65, proportional:true
                               stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                       Stop {offset: 1.0 color: Color.SILVER}]
               }
          },


               // Cut top of cup
               Rectangle{stroke: Color.WHITE fill: Color.WHITE 
                         x: 25 y: 50 width: 150 height: 50} 
     ]
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

After that, I just added a couple more ellipses to make the outer and inner rims:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          },

         // Recessed plate center
           Ellipse{centerX: 0 centerY: 5 radiusX: 90 radiusY: 22
                fill: RadialGradient{
                          centerX: 0.5 centerY: 0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ]
}

def cupGroup = Group {

     translateX: 152
     translateY: 20

     content: [
               // Cup body
               Circle {centerX: 100  centerY: 100 radius: 50
                    fill: RadialGradient {
                               centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY: .65, proportional:true
                               stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                       Stop {offset: 1.0 color: Color.SILVER}]
               }
          },

               // Cut top of cup
               Rectangle{stroke: Color.WHITE fill: Color.WHITE 
                         x: 25 y: 50 width: 150 height: 50},

               // Outer rim
               Ellipse{fill: Color.WHITE centerX: 100 centerY: 100 radiusX: 50 radiusY: 8},

               // Inner rim
               Ellipse{centerX: 100 centerY: 100 radiusX: 48 radiusY: 7 //inner rim
                       fill: RadialGradient {
                                             centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY:.4, proportional:true
                                             stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                                     Stop {offset: 1.0 color: Color.SILVER}]
                       }
               }
     ]
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

Things are looking good! But the cup is still too small. So to make the cup "grow", I just scaled the entire cup group upwards. I actually scaled the y axis slightly more, so as to squish the cup inwards a little to shape it more like an egg:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          },

         // Recessed plate center
           Ellipse{centerX: 0 centerY: 5 radiusX: 90 radiusY: 22
                fill: RadialGradient{
                          centerX: 0.5 centerY: 0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ]
}

def cupGroup = Group {

     translateX: 152
     translateY: 20
     scaleX: 3.0
     scaleY: 4.0

     content: [
               // Cup body
               Circle {centerX: 100  centerY: 100 radius: 50
                    fill: RadialGradient {
                               centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY: .65, proportional:true
                               stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                       Stop {offset: 1.0 color: Color.SILVER}]
               }
          },

               // Cut top of cup
               Rectangle{stroke: Color.WHITE fill: Color.WHITE 
                         x: 25 y: 50 width: 150 height: 50},

               // Outer rim
               Ellipse{fill: Color.WHITE centerX: 100 centerY: 100 radiusX: 50 radiusY: 8},

               // Inner rim
               Ellipse{centerX: 100 centerY: 100 radiusX: 48 radiusY: 7 //inner rim
                       fill: RadialGradient {
                                             centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY:.4, proportional:true
                                             stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                                     Stop {offset: 1.0 color: Color.SILVER}]
                       }
               },
     ]
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

Filling the Cup

Now it's time to fill the cup! For this I made a custom shape from the intersection of the inner rim and a new coffee-colored ellipse. The built-in ShapeIntersect class makes this a trivial matter:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

def plateGroup = Group {

translateX: 250
translateY: 300

 content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               }
          },

         // Recessed plate center
           Ellipse{centerX: 0 centerY: 5 radiusX: 90 radiusY: 22
                fill: RadialGradient{
                          centerX: 0.5 centerY: 0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ]
}

def cupGroup = Group {

     translateX: 152
     translateY: 20
     scaleX: 3.0
     scaleY: 4.0

     content: [
               // Cup body
               Circle {centerX: 100  centerY: 100 radius: 50
                    fill: RadialGradient {
                               centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY: .65, proportional:true
                               stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                       Stop {offset: 1.0 color: Color.SILVER}]
               }
          },

          // Cut top of cup
          Rectangle{stroke: Color.WHITE fill: Color.WHITE 
                    x: 25 y: 50 width: 150 height: 50},

          // Outer rim
          Ellipse{fill: Color.WHITE centerX: 100 centerY: 100 radiusX: 50 radiusY: 8},

          // Inner rim
          Ellipse{centerX: 100 centerY: 100 radiusX: 48 radiusY: 7 //inner rim
                  fill: RadialGradient {
                                        centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY:.4, proportional:true
                                        stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                                Stop {offset: 1.0 color: Color.SILVER}]
                  }
          },
          
         // Create "coffee in cup" by intersecting coffee ellipse with inner rim ellipse
         ShapeIntersect {

              fill: Color.SADDLEBROWN

              //Inner Rim
              a: Ellipse{centerX:100 centerY:100 radiusX:48 radiusY:7} // inner rim dimensions

              //Coffee
              b: Ellipse{centerX:100 centerY:102 radiusX:46 radiusY:6} // coffee dimensions
         }
     ]
}

Stage {
    title: "Coffee Cup"
    visible: true
    scene: Scene {
         width: 500
         height: 500
         content: [plateGroup,cupGroup]
     }
}

And finally, I gave the whole thing a little extra class by setting the background to black:

import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.paint.Stop;
import javafx.scene.paint.RadialGradient;

def BGCOLOR = Color.BLACK;

def plateGroup = Group {

     translateX: 250
     translateY: 300

     content: [

          // The gray ellipse under the plate
          Ellipse{centerX:0 centerY:10 radiusX:160 radiusY:50 fill:Color.DIMGRAY},

          // The thin "lip" of the plate (provides a sense of 3D)
          Ellipse{centerX:0 centerY:3  radiusX:170 radiusY:50 fill:Color.LAVENDER},

          // The large plate ellipse
          Ellipse{centerX:0 centerY:0  radiusX:170 radiusY:50
          fill:RadialGradient{
                    centerX:0.5 centerY:0.75
                    stops:[Stop {offset: 0.0 color: Color.WHITESMOKE},
                           Stop {offset: 0.5 color: Color.LIGHTGRAY},
                           Stop {offset: 1.0 color: Color.DARKGRAY}]
               } 
          },

          // Recessed plate center
           Ellipse{
                centerX:0 centerY:5 radiusX:90 radiusY:22
                fill:RadialGradient{
                          centerX:0.5 centerY:0.75
                          stops:[Stop {offset: 0.0 color: Color.BLACK},
                                 Stop {offset: 0.4 color: Color.LIGHTGRAY},
                                 Stop {offset: 1.0 color: Color.GHOSTWHITE}]
                     }
          }
     ] 
} 

def cupGroup = Group {
  
     translateX: 152
     translateY: 20
     scaleX: 3.0
     scaleY: 4.0

     content: [
               // Cup body
               Circle {centerX: 100  centerY: 100 radius: 50
                    fill: RadialGradient {
                               centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY:.65, proportional:true
                               stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                       Stop {offset: 1.0 color: Color.SILVER}]
                             }
                      },

               // Cut top of cup
               Rectangle{stroke: BGCOLOR fill: BGCOLOR
                         x:25 y:50 width:150 height:50},

               // Outer rim
               Ellipse{fill: Color.WHITE centerX:100 centerY:100 radiusX:50 radiusY:8},

               // Inner rim
               Ellipse{centerX:100 centerY:100 radiusX:48 radiusY:7 //inner rim
                       fill: RadialGradient {
                                             centerX: 0.4 centerY: 0.0 focusX: 0.5 focusY:.4, proportional:true
                                             stops: [Stop {offset: 0.0 color: Color.GHOSTWHITE},
                                                     Stop {offset: 1.0 color: Color.SILVER}]
                       }
               },

               // Create "coffee in cup" by intersecting coffee ellipse with inner rim ellipse
               ShapeIntersect {

                    fill:Color.SADDLEBROWN

                    //Inner Rim
                    a: Ellipse{centerX:100 centerY:100 radiusX:48 radiusY:7} // inner rim dimensions

                    //Coffee
                    b: Ellipse{centerX:100 centerY:102 radiusX:46 radiusY:6} // coffee dimensions
               }
     ]
}

Stage {
    title: "Coffee Cup"
    width: 500
    height: 500
    visible: true
    scene: Scene {
         fill: BGCOLOR
         content: [plateGroup,cupGroup]
     }
}

Conclusion and Future Steps

In conclusion, I found my first attempt at GUI programming with the 1.0 SDK to be quite successful, and ultimately a lot of fun. The declarative programming model is easy to use. Creating sophisticated visual effects becomes almost effortless. The most time-consuming part of the entire project was just tweaking the different gradient values to get the lighting the way I wanted. But the declarative nature of this language really made the actual programming a breeze. I'm really looking forward to what this language can do when it's placed into the hands of real graphic designers!

I'm stopping here because this is what I was able to accomplish in a single afternoon. From here the cup needs a handle and some extra decorations on its face. It would also be great to use key frame animation to add in a steam effect. If you're reading this and would like to add them in, feel free to post your solutions!

-- Scott Hommel

pageicon Tuesday Dec 09, 2008

JavaFX on Facebook

Some folks at Sun have created the first JavaFX application to run on Facebook. If you have a Facebook account, please try it out! (And if you don't have a Facebook account, it's free.)

The picture puzzle app runs on any browser supported by JavaFX, although you get more functionality if you are running JRE 6u10 or better.

To play with the jigsaw puzzle:

  1. Login to Facebook.
  2. Search on JavaFX and from the results select JavaFXPicturePuzzle — it should be the second item listed. (It's located at http://apps.facebook.com/javafxpicturepuzzle/Puzzle.)
  3. Select Go to Application and accept the security questions when prompted.
  4. Bookmark the app so that you can easily find it again — the Bookmark JavaFXPicturePuzzle button is at the bottom of the page.
  5. Please share with your friends by selecting the Share with Friends tab near the top of the page.

Let us know what you think!

-- Sharon Zakhour

pageicon Monday Dec 08, 2008

JavaFX is here!!

Released late last week, JavaFX 1.0 is here!!!

My team created two of the tutorials for JavaFX:

Please check it out and let us know what you think!

Sharon Zakhour

pageicon Friday Oct 31, 2008

Sun in Second Life

Have you tried Second Life yet? Probably you have at least heard of this internet-based virtual reality game, though you might have heard about its more salacious side. And yes, that does exist.

But Second Life is far more than that. It's an enormous and varied community — a rich place for people and activities of all sorts to interact and explore.

And did you know that Sun Microsystems has a presence in Second Life? Sun has three public sims and hosts a variety of events, such as the events held on our new Solaris campus.

How do you find us? You can search Places within SL, but here are Sun's Second Life URLS (SLURLs). You can click these links in your browser and they will launch Second Life (or open a Teleport window within the app):

Sun is hosting a Halloween party at Club Java on October 31st, 8am SLT. (Second Life Time is equivalent to Pacific time.) There will be a costume contest with a $1000L prize for best costume (Linden dollars are the currency used in SL.) There will also be a live DJ.

Above my avatar is modeling the costume I prepared for the event. (The Headless HUD with facial expressions is available from Tortec.)

At some point, we may host a tutorial related event in Second Life. Would you find that interesting? Sun hosts other talks and events on its public sims. There are also freebies, such as t-shirts, backpacks, etc. (Of the virtual variety, of course.)

If you haven't yet tried Second Life, here is a good opportunity. You only need download the application from secondlife.com, create a new account on the website, log in and voila — it's completely free.

I hope to see you at the Halloween party!

-- Sharon Zakhour

pageicon Wednesday Sep 24, 2008

Link to the Latest API Specification in Japanese

Last week I posted about the new link that will always point to the latest API specification: http://java.sun.com/javase/current/docs/api/index.html.

We received feedback from Manabu Nakamura asking us to provide the same link for the Japanese translation.

Ask and you shall receive.

It has gone live today: http://java.sun.com/javase/current/ja/docs/ja/index.html.

Thanks for the great idea, Manabu!!

-- Sharon Zakhour

pageicon Thursday Sep 18, 2008

Link to the Latest API Specification

Up until now, if you wanted to view the Java API, you had to specify a particular release of the JDK. For example: Likewise, if you wanted to link to the API specification, you had to hardcode the release into your documentation. This can lead to stale links as newer versions of the JDK are released and older versions are EOL'd.

We are introducing a new link that will always take you to the latest API specification. If you create a link to (or bookmark) this new URL, you are guaranteed to always be linked to the latest documentation. Currently it links to the JDK 6 API spec, but it will take you to the JDK 7 API spec when it is released.

We hope you find this to be handy!

-- Sharon Zakhour


« November 2009
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
12
14
15
16
18
19
20
21
22
23
25
26
27
28
29
30
     
       
Today

Feeds

Search this blog

Links

Weblog menu

Today's referrers

Today's Page Hits: 583