Skip to main content

JavaFX Script Doodles, #2: a tabbed rectangle

Posted by joshy on February 18, 2008 at 6:27 PM PST

Before I dive into my second doodle I'd like to mention the following Groodle. Allow me to explain. Andres Almiray saw my first JavaFX Doodle and decided to recreate it using the GraphicsBuilder syntax of Groovy; hence a Groodle! :) His first version is verbose, but later he updated it using the new alias syntax to be more compact. JavaFX is still a more concise syntax (IMHO), but Groovy is getting close and certainly has it's own strengths. I hope in the future Groovy will be another great way to build graphically rich apps on the Java platform. After all, why have one awesome way to build apps when you can have two! Be sure to watch Andres' excellent blog for updates.

Now, on to the next doodle.

A Tabbed Round Rectangle

This is another sample for you to paste into NetBeans. It's a tabbed rectangle that looks like this:

doodle2_basic.png
Basic TabRect

Here's the basic code. I started by subclassing CompositeNode and defining the attributes that I want to expose, which is mostly the same ones as the RoundRectangle.

import javafx.ui.canvas.*;
import javafx.ui.*;

public class TabRect extends CompositeNode {
    attribute fill: Paint;
    attribute stroke: Paint;
    attribute x: Number;
    attribute y: Number;
    attribute width: Number;
    attribute height: Number;
    attribute tabSize: Number;
    attribute strokeWidth: Number;
    attribute arc: Number;
}

attribute TabRect.fill = red;
attribute TabRect.stroke = black;
attribute TabRect.x = 0;
attribute TabRect.y = 0;
attribute TabRect.width = 100;
attribute TabRect.height = 50;
attribute TabRect.tabSize = 10;
attribute TabRect.strokeWidth = 3;
attribute TabRect.arc = 10;

So that's pretty straight forward. A clean definition with decent defaults. Good defaults are always important, since it lets developers get started right away. Now I could create this by drawing a rotated rectangle for the tab on top of a regular round rectangle, but that wouldn't be very dynamic. Really I want something that grows and shrinks properly. Then I can use it in cool transition effects, (more on that later). So instead of doing some funky shape unions I just made the shape out of curves and line segments. Note the bind statements everywhere.

operation TabRect.composeNode() {
    return Group {
        transform: bind [translate(x,y)]
        content: [Path {
   
            fill: bind fill
            stroke: bind stroke
            strokeWidth: bind strokeWidth
            d:[
                MoveTo{x: 0, y: bind arc},
                LineTo{x: 0, y: bind height-arc},
                ArcTo {x: bind arc, y: bind height, rx: bind arc, ry: bind arc },
                LineTo{x: bind (width/2-tabSize), y:bind height},
                LineTo{x: bind width/2,y:bind height+tabSize},
                LineTo{x:bind width/2+tabSize,y:bind height},
                LineTo{x:bind width-arc, y: bind height},
                ArcTo {x: bind width, y: bind height-arc, rx: bind arc, ry: bind arc },
                LineTo{x:bind width, y: bind arc},
                ArcTo {x: bind width-arc, y: 0, rx: bind arc, ry: bind arc },
                LineTo{x:bind arc, y: 0},
                ArcTo {x: 0, y: bind arc, rx: bind arc, ry: bind arc },
            ]
            transform: [translate(10.0,10.0)]
        }]
    };
}

It's those bind statements above which contain the magic. Each part of the shape is defined in terms of the height, width, tabSize, and arc variables. This means you can animate those properties and the shape will automatically adapt, no special updating code required.

To use this new shape, just create an instance like this:

TabRect{ tabSize: 10, strokeWidth: 3, width: 100, height: 50};

That will give you a decent looking shape but how about some animation? A nice transition would be handy. The code below does this by changing the height, tabSize, arc, and opacity over one second. The tab nicely fades in and grows down. This would be a nice effect to have when you rollover a waypoint, for example.

var op = 0;
var tab = TabRect{ var: me, tabSize: 10, opacity: bind op, strokeWidth: 3};

Group {
    content: [
    tab,   
    Rect { x: 200, y: 50, fill: red, width: 20, height: 20,
        onMousePressed: operation(e) {
            tab.tabSize = [0..10] dur 300 delay 1000;
            tab.height = [0 .. 100] dur 1000;
            tab.arc = [0 .. 10] dur 1000;
            op = [0, 0.1 .. 1.0] dur 1000;
        }
    }
    ]
}

And here's what this would look like. Notice the delay 1000 for the tabSize part which makes the tab pop in after the rest of the shape, creating a sort of cartoon like effect. (And yes, one day these doodles will be inline applets, but the compiler support isn't quite there yet. We are working very hard and will have something soon. Stay tuned.)

doodle2_animated.png
Final TabRect with animation.

Enjoy. Any ideas for more doodles?

Comments

I have been looking for a simple way to display RDBMS data in a desktop application. My observation is posted here. Seems to be too much code and too many objects for a common task. Is it too much to wish for a swing jDBTable component that would work something like this (with all the nice BeansBindings happening in the background):

CachedResultSet rs = ResultSet.executeQuery();
jDBTable j = new jDBTable(rs);

the ideal jDBTable would connect to the ResultSet while the frame is being rendered, so that it would be possible for users to select columns to display in a dialog. The JSF people have already accomplished most of this for the web.

Here is the link to Groodle #2 as promised: http://jroller.com/aalmiray/entry/gfx_doodle_2 Keep it up!

This is another sample for you to paste into NetBeans.

It might be that I'm stupid, but I wasted a certain amount of time trying to get this sample to do something. It's not enough to paste it into NetBeans. You also have to click on the tiny preview icon above the editor window where you've pasted the code. The NetBeans experience leaves something to be desired here: the function of this icon isn't available on any menu (that I could find) and the familiar function Run, which is available through menus and a much bigger button, doesn't actually do anything useful.

Can u please show how we can animate java fx components

Thanks for the kind words Joshua, I'll be sure to let you know when Groodle #2 is ready =-) Do you think you could put a webstart demo or a flash movie? I'll surely love to see your doodles in action.