Monday Oct 05, 2009

ListView control

Full source code for the project is available here - click here


How to create a list view of your own:

Step 1: Create a model by extending com.sun.list.ListModal
define your data model in this class.
example :

public class ExpenseInCategory extends ListModal {

    public var amountSpent: Number;
    public var category: Category;
    public var percentSpent: Integer;

    public override function toString() : String {
        "Expenses in {category} is {amountSpent} percentwise {percentSpent} Size of transactions is : {sizeof(transactions)}";
    }
}


Step 2:

extend the com.sun.list.ListItem  class and override cloneNode() and create() method.

in the create method you should specify how to  draw the item in ListView.  I have given two implementation for the ListItem  TextItem ( contains only Text node ) and categoryItem ( contains text , amount spend and percentage).
Example:
public class ExpenseInCategoryListItem extends ListItem{

    def font: Font = Font.font("Arial", FontWeight.BOLD, 12);
    def font1: Font = Font.font("Arial",10);

    public override function cloneNode():ListItem {
        ExpenseInCategoryListItem{
            item:item
            width:width
            height:height
            selected:selected
        }
    }

    public override function create():Node{
        var expense = VBox {
            translateY:3
            spacing:5
            content: [
                Text{
                    content: bind (item as ExpenseInCategory).category.toString()
                    font:font
                    fill: Color.MAROON
                },
                HBox {
                    spacing: 60
                    content: [
                        Text{
                            content:bind "${(item as ExpenseInCategory).amountSpent}"
                            font:bind font1
                            fill:Color.BLUE
                        },
                        Text{
                            //translateY:bind (-height)
                            content:bind "{(item as ExpenseInCategory).percentSpent}%"
                            font:bind font1
                            fill:Color.BLUE
                        }
                    ]
                }
            ]
        }
        Group{
            content: [rectangle,expense]
        }       
    }
}


Step 3:
Extend the factory and specify how to create your ListItem.  ListView will use this factory to create the list item.
Example:
public class ExpenseInCategoryFactory extends ListItemFactory{
    public override function create():ListItem{
        ExpenseInCategoryListItem{
        }
    }
}

Now testing your list item.
Step1: Create an array of Model

var categories : ExpenseInCategory[] =
      [ExpenseInCategory{category: Category {name : "Health"} amountSpent:100 percentSpent:10},
       ExpenseInCategory{category: Category {name : "Entertainment"} amountSpent:200 percentSpent:20},
       ExpenseInCategory{category: Category {name : "Car"} amountSpent:400 percentSpent:40},
       ExpenseInCategory{category: Category {name : "Education"} amountSpent:200 percentSpent:20},
       ExpenseInCategory{category: Category {name : "Apparel"} amountSpent:100 percentSpent:10}
       ExpenseInCategory{category: Category {name : "Medical"} amountSpent:100 percentSpent:10}
       ];

Step2: Create the listView
var chartListView = ListView{
       factory: ExpenseInCategoryFactory{}
       listItems: categories
       listHeight: 300
       listWidth: 240
       slotHeight: 35
       };

Are you a JavaFX user? Unleash your opinion! Take a short survey and tell us what you think: http://alturl.com/fwk2

I encourage all JavaFX users to take this survey  your feedbacks  are very important for JavaFX coming release. 

 Thanks

Saturday Aug 08, 2009

JSF-JavaFX

JSF is specification from Sun Micro Systems. Popular implementations are MyFaces from Apache, ADF from Oracle, Reference implementation from sun etc.

I would like to discuss about creating a custom JavaFX component in JSF. Using this you can embedd JavaFX easily in jsp pages. You can

use these component just like any other tag.
Example
  <jfx:applet id:"TestApplet"  code="test.class" archive="test.jar" draggable="true" width="400" height="400"/>

How to create a custom JavaFX component:

Step1 : Creating JavaFXCompoent by extending UIComponentBase.

public class JavaFXComponent extends UIComponentBase {

    @Override
    public String getFamily() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void encodeEnd(FacesContext context) throws IOException {      
       String archive = (String)getAttributes().get("archive");
       String draggable = (String)getAttributes().get("draggable");
       String width = (String)getAttributes().get("width");
       ...
              String script = "<script src=" + javafx_script +"></script>\n" +
                "<script> \n" +
                "javafx(\n" +
                    "{\n" +
                          "archive:"+archive +",\n"+
                          "draggable:"+ draggable +",\n"+
         .....
                ");\n" +
                "</script>";
     }
Here is the complete JavaFXComponent classPlace this file under source directory.
Register this class name in faces-config.xml step3.

Step 2: Create the Tag handler by extending UIComponentELTag .

public class JavaFXTagHandler extends UIComponentELTag {

    private String id;
    private String archive;
    private String code;
   ...

    ValueExpression ve;
    FacesContext fc = FacesContext.getCurrentInstance();
    ExpressionFactory factory =  fc.getApplication().getExpressionFactory();


    private void setValue(UIComponent component, String name, String value) {
        if (value != null) {
            ve = factory.createValueExpression(fc.getELContext(), value, String.class);
            component.setValueExpression(name, ve);
        }
    }

    @Override
    protected void setProperties(UIComponent component) {
        super.setProperties(component);
        setValue(component, "id", id);
        setValue(component, "archive", archive);
....
Register this class in tld file  see step4.
Here is complete JavaFXTagHandler class

Step3: Adding JavaFXComponet in faces-config.xml file.

<faces-config>

    <component>
        <component-type>JavaFX</component-type>
        <component-class>com.sun.training.JavaFXComponent</component-class>
    </component>
  ....
</faces-config>
faces-config.xml should be placed WEB-INF directory.

Step4: Creating the javafx.tld file .

<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
  <tlib-version>1.0</tlib-version>
  <short-name>javafx</short-name>
  <uri>http://java.sun.com/jsf/javafx/</uri>
    <tag>
        <name>JavaFX</name>
        <tagclass>com.sun.training.JavaFXTagHandler</tagclass>
        <bodycontent>JSP</bodycontent>
        <info>
            This is a custom JavaFX applet component
        </info>
        <attribute>
            <name>archive</name>
            <required>true</required>
        </attribute>
.......
Refer here for the complete tld file .
Create this file under WEB-INF or under its subdirectories.

I thought this would be usefull for your web pages.

Monday Jul 27, 2009

For Applet mode, click on above image

For standalone mode

source code - click here

Monday Jul 20, 2009

  The JavaFX AppletStageExtension provides browser specific functonality to the common Stage running in a script. Its primary function is to assist in the transition of a script dragged from a broswer environment and put into a desktop environment. The AppletStageExtension has two different use cases depending on the value of useDefaultClose.

Applet Stage Extension

   

For Applet mode, click on above image.

    Source code at a glance. 
var url1:String = FX.getArgument("clickTag1") as String;
var url2:String = FX.getArgument("clickTag2") as String;
var applet = FX.getArgument("javafx.applet") as java.applet.Applet;
Read the arguments clickTag1 and clickTag2 specified in FX Applet script as url1 and url2. Get the applet object. [
javafx(
        {
              archive: "AppDeployDemo.jar",
              width: 400,
              height: 600,
              code: "AppDeployDemo",
              name: "Java FX AppDeploy Demo"
        }, 
        {
             draggable: "true",
             clickTag1: "http://www.pogo.com",
             clickTag2: "http://www.zembly.com"

        }
    );
] ....
Rectangle {....             onMouseClicked: function(e: MouseEvent): Void {
                  AppletStageExtension.showDocument(url1);
            }
Requests that the browser to show the web page indicated by the url1 argument, which will load the url1 in the same page where the applet is running.
Rectangle {....            onMouseClicked: function(e: MouseEvent): Void {
                  AppletStageExtension.showDocument(url2,"New Javafx window");
            }

Requests that the browser show the web page ind icated by the url2 argument. The target argument indicates in which HTML frame the document is to be displayed. The target argument is interpreted as follows:

Target ArgumentDescription
"_self" Show in the window and frame that contain the applet.
"_parent"Show in the applet's parent frame. If the applet's frame has no parent frame, acts the same as "_self".
"_top" Show in the top-level frame of the applet's window. If the applet's frame is the top-level frame, acts the same as "_self".
"_blank" Show in a new, unnamed top-level window.
nameShow in the frame or window named name. If a target named name does not already exist, a new top-level window with the specified name is created, and the document is shown there.

Note that the browser is free to ignore showDocument. This method has no effect if not running in an applet environment.

var s: Stage = Stage {
    title: "AppDeploy Demo" .....
extensions: [ AppletStageExtension {             shouldDragStart: function(e: MouseEvent): Boolean {
                println("AppDeployDemo.shouldDragStart");
                return e.shiftDown and e.primaryButtonDown;
            }
            onDragStarted: function(): Void {
                println("AppDeployDemo.onDragStart");
            }
            onDragFinished: function(): Void {
                println("AppDeployDemo.onDragFinished");
            }
            onAppletRestored: function(): Void {
                println("AppDeployDemo.onAppletRestored");
            }
            useDefaultClose: false
} ]}
onDragStarted - This function is called at the start of the browser applet drag sequence onDragFinished - This function is called to indicate that the browser applet drag sequence has completed shouldDragStart - This function is called by the browser at the start of a mouse event that might cause a drag out of the browser. We can override the default drag behaviour using this function. Here Shift + Left Mouse Button is used for dragging the applet out. onAppletRestored - This function is called after the out of browser applet has been closed and returned to its environment within the browser. useDefaultClose - This attribute designates whether the default close box behvior is to be used once the applet has been dragged out of the browser, or whether the developer will be taking care of presenting the graphical close mechanism and taking care closing the Stage programmatically. ...
var jsArg1 = ["jsobject.call  JS Alert Test"];
var jsArg2:String = "alert('Alert Test using eval from Java Applet')";
var jsobject:JSObject = JSObject.getWindow(applet);
jsobject.call("alert", jsArg1);
jsobject.eval(jsArg2);
You can use netscape.javascript.JSObject to call a Java Script method.

Thursday Jul 02, 2009

Async Task APIs are located in javafx.async package.  These APIs provides a way of starting, stopping and tracking code that does not run on the JavaFX event dispatch thread.

Now let us see  how we can use this API.

 Step1:  implement  RunnableFuture Interface and create you Task.

For example -

public class MyTask implements RunnableFuture {

public void run() throws Exception {
   //Place your code which you want to execute.
   println("Executing the task...");   
}

}

Note: Only Java Tasks can be specified here. 

Step2: Create JavaTaskBase in your FX code and in create() method return a instance of MyTask.

var task = JavaTaskBase {

public override function create(): RunnableFuture{
        return new MyTask() as RunnableFuture;
}
onDone: function():Void {  println("I am done..");}
onStart : function():Void {  println("About to start");

}

 task.start();

Tuesday Jun 30, 2009

This blog coveres most of the features of WebServices (javafx.io.http.*,javafx.data.*) in JavaFX1.2

Bulk Data Read/Write  and Atom/RSS Feed Parsers

[Read More]

Thursday Jun 18, 2009

Let us see how we can create flying photos.  Images coming from the center and moving to different corners of the screen. This can be acheived by combining two transitions to ImageView.  

TranslateTransition and ScaleTransition.

TranslateTransition will translate images from center to different corners. Where as ScaleTransition will scale the images to get a 3D effect.

Here is the code snipplet 

public class FlyingImage extends CustomNode{

    public var stageWidth:Number = 1024;
    public var stageHeight:Number = 750;


    public var imageView = ImageView {
        fitWidth: 2
        fitHeight: 2
        preserveRatio: true
    }

    public var url : String on replace {
        if(url != null) {
            imageView.image = Image {
                url: url
                backgroundLoading: true
            }
            //visible = false;

        }
    }

    /*var progress = bind imageView.image.progress on replace {
        if(progress >= 50.0) {
            visible = true;
            play();
        }
    }*/


    var scaleT: ScaleTransition = ScaleTransition {
        node:this
        fromX:1.0
        fromY:1.0
        toX: 50.0
        toY: 50.0
        duration: 10s
    }

    var point = getNextPoint();


    var translateT: TranslateTransition = TranslateTransition {
        node:this
        fromX: stageWidth / 2
        fromY: stageHeight / 2
        toX: point.x
        toY: point.y
        duration:10s
    }

    var transition: Timeline = Timeline{
        repeatCount: Timeline.INDEFINITE
        keyFrames: [
            KeyFrame{
                time: 10s
                action: function(){
                    translateT.playFromStart();
                    scaleT.playFromStart();
                }
            }
        ]

    }

    function play(){
        transition.play();
    }

    override function create():Node {
        cursor = Cursor.HAND;
        blocksMouse = true;
        //        var borderRect = Rectangle {
        //            width: bind imageView.boundsInLocal.width
        //            height: bind imageView.boundsInLocal.height
        //            strokeWidth: 0.03
        //            stroke: Color.WHITE
        //            arcWidth: 0.5
        //            arcHeight: 0.5
        //        }
        play();
        Group {
            translateX: bind stageWidth / 2
            translateY: bind stageHeight / 2
            content: [ imageView ]
        }


    }

}

    var random = new Random();
    def maxPoint  = 15;
    var pointIndex = 0;

    class Point {
        public var x :Number;
        public var y :Number;
    }
    function getNextPoint():Point{
        var stageWidth = 1024;
        var stageHeight = 750;
        var points :Point[]= [
            Point{
                x: -stageWidth /2 ,
                y:-stageHeight /2},
            Point{
                x: stageWidth / 2 ,
                y:stageHeight / 2},
            Point{
                x: stageWidth / 2 ,
                y:-stageHeight /2},
            Point{
                x: -stageWidth / 2 ,
                y: stageHeight /2},
            Point{
                x: -stageWidth /2 ,
                y: -random.nextInt(stageHeight / 2)},
            Point{
                x: stageWidth / 2 ,
                y: random.nextInt(stageHeight / 2)},
            Point{
                x: random.nextInt(stageWidth / 2) ,
                y:-stageHeight /2},
            Point{
                x: -random.nextInt(stageWidth / 2) ,
                y: stageHeight /2},
        ];
        var point = points[0];
        if ( pointIndex < 8){
            point = points[pointIndex++];
        }else {
            pointIndex = 0;
        }
        return point;       
    }


Saturday May 09, 2009

javafxpacakger is a very good utility provided by javafx team. This was missing in java. We need to use javac , jar , keytool, jarsigner etc for packaging in java.  Where as it is very simple in JavaFX  - just by pointing the source (-src) directory and Main class name (-appClass ) we can generate .jar , .html  and .jnlp file.

 Here is some more information on javafxpacakger.

Simplest form of javafxpackager

javafxpacakger -src  <sourcedir> -appClass <main class name>

More options.

-res   represent the resource directory if you have images from different directory.

Example:  mySrc/com/xyz/a.fx    myResource/com/xyz/play.png  .  

javafxpackager -src  mySrc  -res myResource  -appClass  com.xyz.a

-d  <your own distribution directory>  using this you can override the default "dist" directory. By default  jar, jnlp, html will be placed  in "dist" directory.

Example:

javafxpackager -src  mySrc  -res myResource  -dist  myDist -appClass  com.xyz.a

Here is the options for changing the codebase, applet widht , height etc.

javafxpackager -src <src> -appVendor <vendor> -appVersion <appVersion>  -appWidth <application width> -appHeight <application height> -appCodebase <codebase> -appClass <Main class>

How to use your own key store.

You can use your own keystore using -keystore option.

Here is how you will create keystore -

$JAVA_HOME/bin/keytool -genkey  -dname "cn=FX packager,ou=CSG,o=SMI,c=US" -alias FxKey -keypass abc123 -keystore FxKeyStore -storepass xyz789 -validity 365

Now you can pass this information to javafxpackager

"$JAVAFX_HOME/bin/javafxpackager" -src src -res resource -appClass Sample -keyStore FxKeystore -keystorepassword xyz789 -keyalias FxKey -keyaliaspassword abc123 -sign

pack option and draggable.

You can use pack options to save download time. if draggable is used applet can be dragged out of browser provided you are using 6u10+

javafxpackager -src src -res resource -draggable -sign -pack200 -appClass <Main class>


Monday May 04, 2009

Here is a simple volume controller for a media player. 

 /**
 * @author Raghu Nair
 */

public class VolumeControl extends CustomNode{

    public-init var mediaPlayer:MediaPlayer;

    var width = Layout.volumeControlWidth;

    var volumeProgress =  bind mediaPlayer.volume with inverse;

    //Background.
    var progressBG : Rectangle = Rectangle {
        width: bind width
        height: bind Layout.iconSize
        fill: Color.LIGHTGRAY
        arcWidth: bind Layout.iconSize
        arcHeight: bind Layout.iconSize
        onMousePressed: function(e:MouseEvent){

            //Control the volume by pressing the mouse.
            println(progress.x);
            println(e.sceneX);
            volumeProgress =  (progress.x - e.sceneX)/width;
        }

    }


    var path = Path {
        elements: [
            MoveTo { x: progressBG.x +5    y: progress.y + Layout.iconSize },
            LineTo { x: progressBG.x + width y: progress.y },
            LineTo { x: progressBG.x + width y: progress.y + Layout.iconSize },
            LineTo { x: progressBG.x + width y: progress.y + Layout.iconSize },
        ]
        fill:Color.DARKBLUE
        clip:Rectangle {
            x: bind progressBG.layoutX
            y: bind progressBG.layoutY
            width: bind width
            height: bind Layout.iconSize
            stroke:Color.TRANSPARENT
            fill: Color.BLACK
            arcWidth: bind Layout.iconSize
            arcHeight: bind Layout.iconSize
        }

    }

    var progress : Rectangle = Rectangle {
        x: bind progressBG.layoutX
        y: bind progressBG.layoutY + 1
        height: bind Layout.iconSize
        width: bind (width * volumeProgress)
        opacity: 0.4
        fill: Color.WHITE
    }

    override public function create():Node {
        Group{
            content: [progressBG,path,progress]
        }
    }
}

 Change the Layout.iconSize to some 45 and width to 120. Your volume controller is ready.

This blog copyright 2009 by Raghu Nair