Archive

Archive for August, 2009

XenonDataGrid M2, Nelson Framework (Milestone 2)*WIP*

August 24th, 2009 Comments off

XenonDataGrid M2, Nelson Framework (Milestone 2)*WIP*

Hi All

Yours truly I have just made Milestone 2.0 release of the Nelson Framework JavaFX Data Grid Component.

Changes

  • You can now scroll through a data grid.
  • There is a new reordering implementation of renderer cells in the grid layer
  • There is a new data structure Mapping and MappingGroup, which maintain position to index coordinate information.
  • Also the “cellLayer” has renamed to “bodyLayer”. The MasterLayer type is now composed of a corner, row header, column header and body cell layers
  • The javafx package structure has now been revised and refactored into separate comprehensible packages.
  • Incremental cell selection strategy has been disabled in the DefaultSelectionStrategy. (It is because the reordering of rows and columns breaks the design and U/X).

Starting with the root package:

Package
Description
com.xenonsoft.nelson.scene.layout This contains the XenonDataGrid AND AbstractXenonDataGrid component
com.xenonsoft.nelson.scene.layout.grid This package contains the table model and constraints class.
com.xenonsoft.nelson.scene.layout.grid.event This package contains event handling types
com.xenonsoft.nelson.scene.layout.grid.layer This package contains the layer classes and mixins
com.xenonsoft.nelson.scene.layout.grid.layout This package contains the data grid layout type, strategy and algorithms
com.xenonsoft.nelson.scene.layout.grid.renderer This package contains the renderer and drawable types.
com.xenonsoft.nelson.scene.layout.grid.selection This package contains the data grid selection context, strategy and algorithm.

Examples

Click on the Screenshots to run the file or the JNLP files to run the examples

Example 1

This is the same as the previous article. Non-scrollable, draggable row and columns. This test verifies the refactoring did not break the U/X of the initial example.

http://xenonsoft.com/jws/XDG-Example-01-1.0-M2.jnlp

Example 2

Here is a brand new example to demonstrate scrolling. Drag a body cell to scroll around the data set, draggable row and columns header cells.

http://xenonsoft.com/jws/XDG-Example-02-1.0-M2.jnlp

Example 3

Here is a brand new example to demonstrate scrolling. The user can use ScrollBars in order to scroll around the data set, draggable row and columns header cells.

http://xenonsoft.com/jws/XDG-Example-03-1.0-M2.jnlp

Example 4

Here is a brand new example to demonstrate scrolling. The user can use ScrollBars in order to scroll around the data set, draggable column header only. Double click a body cell in order to observe a perspective spin animation applied to the lead cell.

http://xenonsoft.com/jws/XDG-Example-04-1.0-M2.jnlp

Example 5

Here is a brand new example to demonstrate scrolling. The user can use ScrollBars in order to scroll around the data set, draggable row header only. Double click a body cell in order to observe animation effect, which happens in the pop up pane.

http://xenonsoft.com/jws/XDG-Example-05-1.0-M2.jnlp

DESIGN NOTE

There a five special scene graphs in the current design of the XDG, which are javafx.scene.Group nodes and are public-read access only. Actually there are currently declared in the AbstractXenonDataGrid. There are used to display cells, background and are very much like the layers in the old JLayerPane. The intention is allow animation and effect to be easily applied to a XDG component.

Name
Description
backPane a pane reserved for a background scenegraph node. (No Pun intended, this property name is shorter than “backgroundPane”)
centralPane a pane reserved for the layout of grid layer cells. The central pane sits above the backPane.
editorPane a pane reserved for the editor cell (TBD). The editor pane sits above the centralPane.
glassPane a pane reserved for the special FXs and animation. The glassPane sits above the  editorPane. (The current implementation of reordering of rows and columns, in the AbstractXenonDataGrid, uses the glassPane)
popupPane a pane reserved for the popup components. The popupPane sits above the glassPane.

See my other AudioBoo: Five Recommendations for JavaFX Table UI Component.

Understanding The Code

Here is the source code for the scrollable data grid, example 2 above.

// BigTableXDGTable.fx
package com.xenonsoft.nelson.scene.layout;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.control.ScrollBar;

import com.xenonsoft.nelson.scene.layout.XenonDataGrid;
import com.xenonsoft.nelson.scene.layout.grid.TableModel;
import com.xenonsoft.nelson.scene.layout.grid.layer.MultiGridLayer;
import com.xenonsoft.nelson.scene.layout.grid.layer.GridLayer;
import com.xenonsoft.nelson.scene.layout.grid.renderer.XenonGridCellRenderer;
import com.xenonsoft.nelson.scene.layout.grid.renderer.XenonGridCellHeaderRenderer;
import com.xenonsoft.nelson.scene.layout.grid.selection.SelectionContext;

/**
 * @author Peter Pilgrim
 */
def MARGIN_WIDTH  = 5.0;
def MARGIN_HEIGHT = 5.0;
def OFFSET = 25.0;
def GAP_SIZE = 3.0;

// XDG size
def GRID_ROWS=8;
def GRID_COLUMNS=8;

// Model matrix size
def MATRIX_ROWS=50;
def MATRIX_COLUMNS=50;
def mt = new Matrix( MATRIX_ROWS, MATRIX_COLUMNS );
for ( r in  [0..mt.getRows()-1] ) {
    for ( c in  [0..mt.getColumns()-1] ) {
        mt.setData( r, c, “Cell_{r}_{c}”);
    }
}

def font: Font = Font { size: 12 };
def headerFont: Font = Font { name: “Arial Bold” size: 12 };

def backFill = LinearGradient {
    startX: 0.0, startY: 0.0, endX: 0.0, endY: 100
    proportional: false
    stops: [
        Stop { offset: 0 color: Color.GRAY },
        Stop { offset: 0.2 color: Color.BLACK }
    ]
}

var scene: Scene;
var dataGrid: XenonDataGrid;
var vertSB: ScrollBar;
var horzSB: ScrollBar;

var myScrollRow : Float = 0 on replace {
    dataGrid.scrollRow = myScrollRow as Integer;
};

var myScrollColumn : Float = 0 on replace {
    dataGrid.scrollColumn = myScrollColumn as Integer;
};

Stage {
    title: “Xenon Data Grid Demo #2 (Scrollable)”
    width: 750
    height: 500
    scene: scene = Scene {
        fill: Color.web(“#F0F0F0″)
        content: [
            vertSB = ScrollBar {
                layoutX: bind scene.width - OFFSET/2
                layoutY: MARGIN_HEIGHT
                width: OFFSET
                height: bind scene.height - ( 2 * MARGIN_HEIGHT + OFFSET + GAP_SIZE)
                min: 0
                max: mt.getRows() - GRID_ROWS
                vertical: true
                value: bind myScrollRow with inverse
            },

            horzSB = ScrollBar {
                layoutX: MARGIN_WIDTH
                layoutY: bind scene.height - OFFSET
                width: bind scene.width - ( 2 * MARGIN_WIDTH + OFFSET + GAP_SIZE)
                height: OFFSET
                min: 1
                max: mt.getColumns() - GRID_COLUMNS
                vertical: false
                value: bind myScrollColumn with inverse
            },

            dataGrid = XenonDataGrid {
                debug: true;

                layoutX: MARGIN_WIDTH
                layoutY: MARGIN_HEIGHT
                width: bind scene.width - (2 * MARGIN_WIDTH + OFFSET + GAP_SIZE )
                height: bind scene.height - ( 2 * MARGIN_HEIGHT + OFFSET + GAP_SIZE )
            
                headerCellFont: headerFont
                cellFont: font;

                masterLayer: MultiGridLayer {
                    cornerLayer:  GridLayer {
                        debug: true
                        rowSize: 1
                        columnSize: 1
                        renderers: [
                            XenonGridCellHeaderRenderer {
                                backgroundFill: Color.DARKGRAY
                                foregroundFill: Color.LIGHTGRAY
                            }
                        ]

                        tableModel: TableModel {
                            rowSize: 1 columnSize: 1 data: “Corner”
                        }
                    }

                    rowHeaderLayer:  GridLayer {
                        debug: true
                        rowSize: GRID_ROWS
                        columnSize: 1
                        renderers: [
                            for ( r in  [0..<GRID_ROWS] ) {
                                XenonGridCellHeaderRenderer {
                                    backgroundFill: backFill
                                    foregroundFill: Color.WHITE
                                }
                            }
                        ]

                        tableModel: TableModel {
                            rowSize: mt.getRows()
                            columnSize: 1
                            data: for ( r in  [0..mt.getRows()-1] ) {
                                ”Row {r}” } }
                    }
                        

                    columnHeaderLayer:  GridLayer {
                        debug: true
                        rowSize: 1
                        columnSize: GRID_COLUMNS
                        renderers: [
                            for ( c in  [0..<GRID_COLUMNS] ) {
                                XenonGridCellHeaderRenderer {
                                    backgroundFill: backFill
                                    foregroundFill: Color.WHITE
                                }
                            }
                        ]

                        tableModel: TableModel {
                            rowSize: 1
                            columnSize: mt.getColumns()
                            data:
                            for ( c in  [0..mt.getColumns()-1] ) {
                                ”Column {c}”
                            }
                        }
                    }

                    bodyLayer:  GridLayer {
                        debug: true
                        rowSize: GRID_ROWS
                        columnSize: GRID_COLUMNS
                        renderers: [
                            for ( r in  [0..<GRID_ROWS] ) {
                                for ( c in  [0..<GRID_COLUMNS] ) {
                                    XenonGridCellRenderer {
                                        backgroundFill: if ( r mod 2 == 1 ) Color.LIGHTGREEN else Color.LIGHTGRAY
                                    }
                                }
                            }
                        ]

                        tableModel: TableModel {
                            rowSize: mt.getRows()
                            columnSize: mt.getColumns()
                            data:
                            for ( r in  [0..mt.getRows()-1] ) {
                                for ( c in  [0..mt.getColumns()-1] ) {
                                if ( c == 2)
                                    ”LONGTEXT {mt.getData( r, c).toString()}”
                                else
                                    mt.getData( r, c).toString()
                                }
                            }
                        }
                    }
                }
            }
        ]
    }
}

dataGrid.selectionStrategy.onUnselection = function ( ctx: SelectionContext ) {
    FX.println(“old selection ( {ctx.selectedRowMin},  {ctx.selectedColumnMin} ) – ( {ctx.selectedRowMax},  {ctx.selectedColumnMax} )”);
}

dataGrid.selectionStrategy.onSelection = function ( ctx: SelectionContext, oldCtx: SelectionContext ) {
    FX.println(“new selection ( {ctx.selectedRowMin},  {ctx.selectedColumnMin} ) – ( {ctx.selectedRowMax},  {ctx.selectedColumnMax} )”);
}

// END

In this example, we create a Java object type, Matrix, which represents our large table (50 rows down and 50 rows across, a grand total of 2500). XDG does not care where the data comes from, because it is contained in a TableModel type. Our scene contains three UI components, two scroll bars, horizontal and vertically respectively and the XeNoNDataGrid.

We have two script variables, myScrollRow and myScrollColumn, to listen to the changes in the scrollbar. There are two triggers on them, which update the XDG scroll position. Two indirect script variable are used indirectly instead of binding, because it allows for future updates in the reverse direction – XDG implementation can update the scroll position.

Pay particularly attention to the code, which declares each ScrollBar and set the maximum value. We avoid out of bound runtime exceptions if we can limit the coordinates to the confines of the table model

So we declare the Scene and scrollbars. We declare the XDG with a MultiGridLayer. We can optionally define the corner, column header and/or row header layers, but we must declare the body layer. The body layer is a GridLayer type, which accepts a sequence of renderer cells and a table model. Notice we set up the rowSize and columnSize of the grid layer’s renderers, which different to the user defined table model bounderies. It is this difference that provides the scrolling ability.

Conclusion

The article introduced the XenonDataGrid and its capabilities in scrolling data sets. The Milestone M2 code is downloadable from Project Kenai in binary and source release.

TODO: Milestone 3 will feature the ability to edit the data and it will show off editor renderer cell(s). There will be a fix to the ProportionalResizeLayoutStrategy (buggy). There will be ability to set the minimum and maximum width and heights of header cells. Finally there will possibly be a better selection model based on ranges.

This is Peter Pilgrim. Out.

STOP PRESS

There is a bug in the reordering of the rows and column, which I won’t fix it in the M2 release. The solution is to change this line 183 in the TableUtils.fx

var value Integer = (mapping.getByB( j ) as IntegerMapping ).getB();

to

var value Integer = (mapping.getByA( j ) as IntegerMapping ).getB();

Download the source code, build the distribution, then recompile the code and build the JAR. This reminds to ask Stephen Chin’s permission to put the JFXtras 0.5 JARs into a Maven Repository in the future.

See you for the M3 release

Categories: Java Tags:

AudioBoo Updates: Nelson Framework M1.0+ Xenon Data Grid *WIP*

August 11th, 2009 Comments off

AudioBoo Updates: Nelson Framework M1.0+ Xenon Data Grid *WIP*

Hi All

Last week I blogged about the XenonDataGrid the JavaFX Table UI component, which I have been working for a while now. The XDG is part of The Nelson Framework.

Because of some snarfu, the original blog entry got mangled. Sorry about that, but you listen to them here in full.

AudioBoo: JavaFX: Design of the XenonDataGrid UI Component Part 1

AudioBoo: JavaFX: Design of the XenonDataGrid UI Component Part 2

Enjoy. Do let me know if you have comments.

PS: The Nelson Framework gains its first other significant committer. Welcome Rustem Suniev., who currently learning and using Scala, but wants to volunteer some JavaFX code. Thanks Rustem, it is very much appreciated. Now that is what I call open source!

This is Peter Pilgrim. Out.



Categories: Java Tags:

Nelson Framework M1.0+ Xenon Data Grid *WIP*

August 7th, 2009 Comments off

Nelson Framework M1.0+ Xenon Data Grid *WIP*

Hi All

Work in progress on Nelson Framework JavaFX Data Grid Component. Yours truly has ported the core framework from JavaFX 1.1 and 1.2. I chose to concentrate on that missing functionality in the component world, a UI Table with a pure scene graph. After a month of dogged part-time work, I reached Milestone 1.0+.

Click on the Screenshot to run the JNLP file.

You can also find this in an AudioBoo http://audioboo.fm/: file.

This version of the XenonDataGrid is quite stable, but you should be aware the codebase is constantly changing. The XDG here is resizable, one can drag row cells up and down by selecting the row header cell (JTable did not do this!). Likewise the column cells can be dragged left or right.

Here are the salient points:

  • Milestone 1.0+ (unreleased) demonstrates the reordering of rows and columns.
  • Separation of the renderable layer model from the table model.
  • Association of table model to a render layer and vice versa
  • Layers contain renderable cells, which contain scene graph nodes
  • User have control of a table model.
  • Composition layers, layers can be contain other layers.
  • MasterLayer type that composed of a corner, row header, column header and normal cell layers
  • Introduce several mixin pure types
  • Abstract implementations of selection and layout algorithms (Fixed dimension and Proportional Layouts)

See my other AudioBoo: Five Recommendations for JavaFX Table UI Component.

TODO: Lots and lots

This is Peter Pilgrim. Out.



Categories: Java Tags:

Calling Out For A London JVM Languages Camp

August 7th, 2009 Comments off

Calling Out For A London JVM Languages Camp

Hi All

Recognising the diversification of the Java platform in recent years,
I am looking to create a unique community event in London.
I am Peter Pilgrim, founder and current organiser of the
JAVAWUG,
London’s best known independent Java community, established
in May 2004! I am also a Java Champion.

So I would like to generate interest for a London JVM Languagues Camp
(or maybe that should be workshop) for the following reasons:

  • Growth: Strong growth in credible languages such as Scala, Groovy, JavaFX, JRuby, Clojure, Fan:
    Developers and designers are interested in languages on the JVM other than Java.
  • Innovation: Developers and designers are clamouring for innovation and waiting
    for the next thing to happen. What we all need is pro-active participation.
  • Reach: We are stronger together when we act on an action together
  • Learning: A software developer career has one guaranteed requirement.
    You must be able to learn. You must have an aptitude for continuous learning.
  • Experience: My own experience at the
    JavaPosse Roundup 2009 in Crested Butte and
    OpenSpace
    Conference

    led to my belief that developers and designer really have to D.I.Y (Do It Yourself).
    In other words, saliently said: Don’t wait for the monkey [company] to feed you.
    Feed your own brain first!
  • Freedom: I have a free weekend in October 10-12th to order to stage, host and/or collaborate
  • Ire: How come the
    Silicon Valley Group
    can organise an event for their region of the world?
    And our beloved London with a population of 7 millions people, can’t do ++++?

You can also find my announcement as an

AudioBoo: Would Like To Arrange The London JVM Languages Code Camp

NB: The reason I have not advertised this under the JAVAWUG brand is because JVM Languages
means an organisation other than Java. Also it respects other communities that already
exist in parallel with the Java groups

So my idea is to have a camp weekend style with these requirements:

  • Saturday (full day) and Sunday (shorter day)
  • Friday night before the camp weekend, optionally, be a set up and introduction
  • Strict rules: Everyone must be ready to go with software, laptop before they can participate the camp day
    begins. This is so we do not waste time installing software during the event.
  • Multiple tracks: JavaFX, Ruby, Groovy, Scala, etc
  • Make it open space in principle, allow folks to self organise.

If you are anyway interested in helping make this idea a reality, please contact me,
now, with subject “LONDON JVM CC” or simply “LJVMCC” at my electronic
mail address of peter dot pilgrim at gmail dot com or tweet me as (peter_pilgrim).  Action Deadline: 18th August 2009.

Thanks. I’m out.

Categories: Java Tags: