Peter Pilgrim is professional software developer, designer and architect. Since 1998 he has worked in the financial services industry, investment banking mainly, developing IT for clients. He is a well known specialist in Java Enterprise Edition (Java EE) technology, focused on the server-side and the implementation of electronic commerce. Peter has built professional Java EE apps for top-tier investment banks such as Lloyds Banking Group, UBS, Credit Suisse, Royal Bank of Scotland and Deutsche Bank. Peter is the 91st Oracle Java Champion. Peter is a DZone MVB and is not an employee of DZone and has posted 34 posts at DZone. You can read more from them at their website. View Full User Profile

JavaFX: Reintroduce Swing JTable

09.01.2008
| 31362 views |
  • submit to reddit

In this blog entry yours truly will explain how to reintroduce the Swing JTable to a JavaFX application. We will mull over why it this valuable component was removed and extol over its virtue. I will show some of my Gmail Client code.

Why JTable Was Removed?

The JTable was removed from the JavaFX, because the FX GUI team are looking to rewrite UI using it with the Project SceneGraph API. The scenegraph is based on modular structure tree layout of graphical object, whereas the components in Swing and AWT components in Java were built from Java 2D and thus are capable of only rendering immediate-mode graphics.

What is is the advantage of a graph of objects? Well it makes it easy to consider each graphic as a node. Each node can combined together in to group of node objects. For each individual node one apply an affine transformation, where one can translate a node by a distance, rotate a node about angle and shear a node across to a parallelogram. You can apply the same affine transformations to a group of node objects. Realise, then, what you can achieve when you have a group of group of nodes. Scenegraph has all of this and also adds light shading, painting effects and filters and shape clipping on each node (SGNode ).

Another way to think of nodes, is to look at the field of computer aided design (CAD). When automative engineers design car they obviously use graphic elements to represent each part of car. A car has an axle, three or more wheels, an engine and usually a steering wheel. Each component of car can be render in a transformation, colour and details that it requires. However you can then rotate the car completely and see all its of constituent move or change as a whole.

Obviously the JTable, then, will have to be redeveloped for Project Scenegraph

What Are The Positives About JTable?

There are plenty of good points to venerable JTable, which has survived the turmoil of Java UI design. We have lived with the JTable, since probably 1998, when it was revealed in a com.sun.java.swing.JTable name. Even back then, it was a really stunning to be able to drag a table column from one end of the view to another column. It was amazing engineering.

It implements a rather good FLYWEIGHT design pattern (see TableCellRenderer, DefaultTableCellRenderer and TableCellEditor).
It can handle a vast amount of data thrown at it.
The data model resides in a TableModel, which is completely divorced the component UI.
It follows the Model View Controller like every other Swing component.

Adding Swing JTable

Sometimes you just cannot live without these advantages. JTable is great if you want to display rows and columns from a database table. If you have already Swing knowledge then you know already how to use and program it. So why not use it?

You can however get the JTable back inside your JavaFX programs. It is reasonably straight forward to reuse any Swing component inside the JavaFX Preview SDK and Subversion release now. You can wrap any JComponent inside a javafx.ext.swing.ComponentView. Therefore you can add a JTable to a scenegraph based JavaFX user interface program easily. Under the hood, the magic is handled by a SGComponent (from Project SceneGraph).

What I will quickly show in this example is my own version of JTable, based alot on studying the code in the Assortis Demo. The Assortis Demo is part of the Subversion openjfx-compiler project. Here is my XenonTable.

/*
* XenonTable.fx
*
* Created on 22-Jul-2008, 00:31:28
*/

package com.xenonsoft.gmailclient.ui;

/**
* @author Peter Pilgrim
*/

import javafx.ext.swing.Component;
import javax.swing.JTable;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.table.TableModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.lang.System;
import java.lang.Exception;

public class XenonTable extends Component {
private attribute table: JTable;

public attribute selectedRows: Integer[];

public attribute selectedColumns: Integer[];

public attribute onRowLeadSelection: function( row: Integer, column: Integer ): Void;
public attribute onColumnLeadSelection: function( row: Integer, column: Integer ): Void;

public attribute rowSelectionAllowed: Boolean = true on replace {
if ( table != null ) {
table.setRowSelectionAllowed( rowSelectionAllowed );
}
};
public attribute columnSelectionAllowed: Boolean = false on replace {
if ( table != null ) {
table.setColumnSelectionAllowed( columnSelectionAllowed );
}
};

public attribute tableDataModel: XenonTableModel on replace {
if ( tableDataModel!= null ){
table.setModel(tableDataModel);
}
};

override function createJComponent(): JComponent {
table = new JTable();
table.setFillsViewportHeight(true);
if ( tableDataModel != null ) {
table.setModel(tableDataModel);
}

var rowListener = ListSelectionListener {
override function valueChanged(e:ListSelectionEvent): Void {
if (e.getValueIsAdjusting()) {
return;
}
System.out.print("ROW SELECTION EVENT ");
debugSelection();

// Compiler bug convert int[] to Integer[]?
var sRows:Integer[] = table.getSelectedRows();
selectedRows = sRows;
fireOnRowLeadSelection( e );
}
};
table.getSelectionModel().addListSelectionListener(rowListener);

var columnListener = ListSelectionListener {
override function valueChanged(e:ListSelectionEvent): Void {
if (e.getValueIsAdjusting()) {
return;
}
System.out.print("COLUMN SELECTION EVENT ");
debugSelection();

// Compiler bug convert int[] to Integer[]?
var sColumns = table.getSelectedColumns();
selectedColumns = sColumns;
fireOnColumnLeadSelection( e );
}
};
table.getColumnModel().getSelectionModel().addListSelectionListener(columnListener);

var scrollPane = new JScrollPane(table);
return scrollPane;
// return table;
}

protected function fireOnRowLeadSelection( e: ListSelectionEvent ): Void {
var row:Integer = table.getSelectionModel().getLeadSelectionIndex();
var column:Integer = table.getColumnModel().getSelectionModel().getLeadSelectionIndex();
if (this.onRowLeadSelection != null ) {
this.onRowLeadSelection( row, column );
}
}

protected function fireOnColumnLeadSelection( e: ListSelectionEvent ): Void {
var row:Integer = table.getSelectionModel().getLeadSelectionIndex();
var column:Integer = table.getColumnModel().getSelectionModel().getLeadSelectionIndex();
if (this.onColumnLeadSelection != null ) {
this.onColumnLeadSelection( row, column );
}
}

protected function debugSelection(): Void {

System.out.print("Lead: {%d table.getSelectionModel().getLeadSelectionIndex()} ");
System.out.println("{%d table.getColumnModel().getSelectionModel().getLeadSelectionIndex()} ");

System.out.print("Selected Rows: ");
var selectedRows: Integer[] = table.getSelectedRows();
for ( r in selectedRows ) {
System.out.print("{%d r} ")
}
System.out.println();
System.out.print("Selected Columns: ");
var selectedColumns: Integer[] = table.getSelectedColumns();
for ( c in selectedColumns ) {
System.out.print("{%d c} ")
}
System.out.println();
}
}


 


Although it looks complicated the above code is really straight forward. In order to create the component in JavaFX, one subclasses from a special node called Component and then one implements the function createJComponent(). The createJComponent creates a JTable and return its wrapped in a JScrollPane.

Published at DZone with permission of Peter Pilgrim, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Andrew McVeigh replied on Mon, 2008/09/01 - 9:44am

i really cannot understand why they can't do zoomable jtables using the scenegraph project.

the scenegraph library replaced the use of Jazz from HCIL. I use Jazz extensively in my work, and it can apply any affine transformation to any swing widget. want a jtable that's double size, rotated 90 degrees and back to front? no problem! how about one that rotates in real-time? again, easy to do with Jazz.

heaven knows why they had to replace Jazz rather than evolving it.  it looks to be a fairly straightforward case of NIH, I think, in making the scenegraph.

Andrew

Chui Tey replied on Mon, 2008/09/01 - 3:57pm

The official word is that mobile devices do not have Swing. Hence, a new node-based Table implementation.

Unfortunately, JavaFX is rather resource intensive. A node-based Table will only be likely suitable for a toy application. I don't think I'd implement my e-mail client using this.

 

Peter Pilgrim replied on Tue, 2008/09/02 - 9:13am in response to: Andrew McVeigh

Andrew

Yes you can do this. If you have the knowledge.

Look at James Weavers blog entries from this month at javafxpert.com http://learnjavafx.typepad.com/weblog/2008/08/tablenode-creat.html for an example of custom TableNode. This is simplified table.

The way the JTable was designed in 1998 is probably not how the JavaSoft [or should that be JavaFXSoft] team would develop it today.

You can create a group container that manages a two grid of Nodes. The problem is how to generalise the concept of a table.

I saw the Dojo Framework struggling with various table implementation version from 0.4 to 0.9 for a number of years. It is difficult to really generalise tables. JTable was a marvellous job with hindsight.

Case #1 Zoomable Table, where you can magnify the whole table of cells.

Case #2 Zoomable Table Cell, where you can manify a cell inside a table.

Case #3 Table with Custom Node. How about a table with video players in row 0 or mp3 players in row 1

I foresee there will special collection tables. Perhaps the Javafxsoft team will create an abstract tablenode concepts and every one else will subclass it, as they did with JTable.

 

 

 

 

 

Peter Pilgrim replied on Tue, 2008/09/02 - 9:19am in response to: Chui Tey

Chui 

This is correct. With the scenegraph CustomNode you can create a table layout component using your grid layout algorithm. For example to draw Text (see javafx.scene.text.Text ). Essentially you write a Group custom container which contains only Text components, then you lay them out in a plane using a coordinate system. You can use the CustomNode#clip facility to constraint overflows. That's the theory.

Chui Tey replied on Wed, 2008/09/03 - 5:55pm in response to: Peter Pilgrim

[quote=peter_pilgrim]The way the JTable was designed in 1998 is probably not how the JavaSoft [or should that be JavaFXSoft] team would develop it today.[/quote]

Interesting comment, Peter.

How would you have tackled JTable differently if you had to do it today? 

Taking a look at data-binding in Netbeans now, and you can see that Sun is now eschewing compilation-time type checking, and instead uses string-based expressions for run-time reflection and binding.

If JTable had originally worked this way, then there would be no TableModel implementation to worry about. Instead JTable could have bound to any sequence object that is indexable. In turn, on JavaFX, it would have made binding to JavaFX classes a cinch.

 

Sergey Surikov replied on Tue, 2009/08/04 - 2:05pm

Too many code

use CRUDfx SDK from http://code.google.com/p/crudfx/
see screenshot with table

Milka Giordano replied on Sun, 2009/11/08 - 11:14pm

What is the use of Crudfx? I never able to learn about CAD and always hire an expert from Freelancer.com. It saves more time and power, though I have to spend some amount of money. They are pretty good anyway. You can use this code "3DPROTOTYPE" to get more benefit from the site. Good luck.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.