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

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;       
    }


Tuesday Apr 28, 2009

The absolute value of rate indicates the speed which the Timeline is to be played, while the sign of rate indicates the direction. A postive value of rate indicates forward play, a negative value indicates backward play and 0.0 to stop a running timeline.

Here is a example to demonstrate rate . 

/**
 * @author raghu
 */
var r = 10;
var x = 10;
var circle =                 Circle {
                    radius: bind r
                    centerX: bind x
                    centerY: 187
                    fill: RadialGradient {
                        centerX:0.0
                        centerY:0.0
                        focusX:0.0
                        focusY:0.0
                        proportional:true
                        stops: [
                            Stop{ color: Color.RED offset:0.5},
                            Stop{ color: Color.WHITE offset:1.0}
                        ]
                    }
                }
;

var timeline = Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: [
        at(0s) { r => 1}
        at(0s) { x => 10 }
        at(10s){ r =>30 tween Interpolator.LINEAR}
        at(10s){ x => 200 tween Interpolator.LINEAR }
    ]

}


timeline.rate = bind <<some variable>>;   // Changing this variable will be change the speed
timeline.play();

Stage {
    title: "Application title"
    width: 250
    height: 500
    scene: Scene {
        content:
                circle
    }
};

Here I am translating a circle -  If rate is set 1 then translation and increase in radius will happen in normal speed - in 10s   x will transalate to 200 and  radius will change to 30. If  I make rate  as -1 . It will reverse the direction 200 to 10  and 30 to 1  in  10 sec. Inverting the rate of a running Timeline will cause the Timeline to reverse direction in place and play back over the portion of the Timeline that has already elapsed.

 If I have to  play this in slow motion I have to use  rate  0.[00-99] . This will be useful when building a game or some thing similar.  To increase the speed you can set rate > 1. 2 means 2 times faster 3 - 3 time faster etc.

Monday Apr 27, 2009

Here is the way you can schedule a task using JavaFX.

Here is the code.
    var timer:Timeline = null;

    public function scheduleAction(timeout:Duration,action:function()) {
        var timer: Timeline = Timeline {
            repeatCount: 1
            keyFrames: KeyFrame {
                time: timeout
                action: action
            }
        }
        timer.play();
    }

You can use this  like this

scheduleAction(5s, function () {  <<your action here >> }

your action will be executed after 5seconds.

Here is progress bar which will be usefull.

     public var width = <max width>;

    var progressBar : Rectangle = Rectangle {
        transalateX: <Place where ever you want>
        transalateY: <Place where ever you want>
        height: 5
        width: bind ((width * progress)/100.0)
        fill: Color.ORANGE

   }


Wednesday Apr 22, 2009

Here is the code for creating a tool tip for any given node.  I have played with opacity of source node. You can remove that part if you dont want. 

/**
 * @author Raghu Nair
 */

public class TooltipNode extends CustomNode{


    /* Source node where you want to show the tool tip */
    public-init var sourceNode:Node;

    /* Tool tip text */
    public-init var tooltip:String;

    /* Width */
    public-init var width :Integer = 80;



    var glowColor = Color.TRANSPARENT;
    override var opacity = 0.0;
    def showTip:Timeline = Timeline {
        keyFrames: [
            at (0s) {
                glowColor => Color.TRANSPARENT;
            opacity => 0.0;
            },
            at (1s) {
                glowColor =>Color.color(0.5, 0.5, 0.5, 0.5);
                opacity => 1.0 tween Interpolator.EASEBOTH;
            },
        ]
    }

    var rectangle:Rectangle = Rectangle{
        translateX: bind ( sourceNode.translateX+(sourceNode.layoutBounds.width - rectangle.layoutBounds.width )/2)
        translateY: bind (( sourceNode.layoutBounds.height/2) + 45);
        fill:Color.YELLOW
        width:width
        height:25
    }

    var text:Text = Text {
        translateX: bind (rectangle.translateX )
        translateY: bind rectangle.translateY+(rectangle.layoutBounds.height / 2) + 3
        font: Font {
            size: 11
        }
        fill: Color.BLUEVIOLET
        content: bind tooltip
    }

    override function create():Node {
        sourceNode.onMouseEntered = function(e:MouseEvent){
            sourceNode.opacity = 1.0;
            showTip.rate = 1.0;
            showTip.playFromStart();
        }
        sourceNode.onMouseExited =  function(e:MouseEvent){
            sourceNode.opacity = 0.7;
            showTip.rate = -1.0;
            opacity = 0.0;
        }
        Group{
            content: [rectangle,text]
       }

    }
}

This blog copyright 2009 by Raghu Nair