Slide for JavaOne 2009 – Bringing JTable to the ... - JIDE Software

wastecypriotInternet and Web Development

Nov 10, 2013 (3 years and 6 months ago)

150 views

TS
-
4706

Bringing JTable to the
Extreme

David Qiao

JIDE Software, Inc.

About JIDE

>
JIDE Software is a Swing component provider

>
Over 12 different products

>
Also provide L&F, UI and icon design service


JIDE Docking Framework


JIDE Grids


JIDE Pivot Grid


JIDE Data Grids


JIDE Desktop Application Framework

2

Goal

>
Explore the internals of JTable

>
Find a way to enhance it to meet requirements

3

JTable: 101

4

JTable

TableModel

TableUI (BasicTableUI)

JTableHeader

TableColumn

TableColumnModel

TableCellRenderer

TableCellEditor

JTable

>
Nothing but a bunch of cells arranged in grid
-
like
layout

>
Not enough in an real world application


5

Possible Enhancements: Table Header

>
AutoFilter (
Excel style filter dropdowns)

>
Multiple Rows in the Header with Column Span
(nested table header)

>
Sortable/
Groupable

>
Show/Hide Columns (right click context menu)

>
Column Auto
-
Fit (double click on the column divider)

6

Possible Enhancements: Table Body

>
Cell Spanning (merge cells)

>
Frozen Rows/Columns (make some rows or columns
not scrollable)

>
Resizable Rows/Columns (drag the grid lines to resize)

>
Cell Styling (row/column stripes, back/foreground
color, font, flashing)

>
TreeTable

>
HierarchicalTable (put other components inside table
under each row)



7

Possible Enhancements: Table Model

>
Sorting

>
Filtering

>
Grouping

>
Caching

>
Paginating

>
JavaBean

Support

>
JDBC or Hibernate Support


8

Possible Enhancements: Renderer/Editor

>
More cell renderers and editors for various data types


Numbers


Color


Date/Calendar


Font


Insets


Array


9

Possible Enhancements: Other

>
State persistence (column order, width, sort order,
selection)

>
Key navigation (i.e. only stop on editable cells)

>
Excel export

>
Non
-
contiguous cell selection

>
Formula (like Excel)

>
Copy and paste (copy is supported by JTable but paste
is missing)

>
Cell validation and row validation

10

Things to Consider

>
Compatible with JTable


JTable is still moving along, there is no reason to start
from scratch.


Won’t break the code for every new JDK release.

>
Compatible with existing code which already uses
JTable


Make migration easier


Developer feels at home


>
Cons: face some limitations

Things we can leverage

>
Subclassing


JTable


BasicTableUI


TableModel

>
Overriding


JTable:
prepareRenderer
,
prepareEditor
,
changeSelection
,
isCellSelected
,
rowAtPoint

etc.


BasicTableUI: paint

>
Leveraging existing
JTable

APIs


listeners, keyboard actions

Case Studies

>
Filtering and Sorting

>
Cell Spanning

>
Cell Styling


13

Case Study: Filtering and Sorting

>
The original TableModel should
NOT
be touched

>
Performance and memory

>
Scalability



14

Demo of
Sortable

and Filterable Feature

15

The solution is …

>
View/Model Conversion


Using a row index mapping to map from the row index
from the actual model to the row index in the view

>
Nothing new


TableColumnModel

is such a view/model conversion
except it is for the columns

16

TableModelWrapper

(or delegate)

>
It wraps any
TableModel
to provide a mapping of row
indices

from the outer model to the inner model

>
Only one method


TableModel

getActualModel
()

>
RowTableModelWrapper



Provides row index mapping


int

getActualRowAt
(
int

visualRowIndex
)


int

getVisualRowAt
(
int

actualRowIndex
)


SortableTableModel

3

0

6

1

0

2

1

3

5

4

2

5

8

6

9

7

7

8

4

9

SortableTableModel

(set to a table)

Actual

TableModel

.

.

.

Implementation of
getValueAt

method

public Object getValueAt(int row, int column) {


if (_indexes != null && (row < 0 || row >= _
indexes.length
)) {


return null;


}


else {


return
_
model
.getValueAt
(
getActualRowAt
(row)
, column);


}


}


where
getActualRowAt

is
_indexes[row]
.

19

FilterableTableModel

0

0

3

1

9

2

3

4

5

6

7

8

9

FilterableTableModel

(set to a table)

Actual

TableModel

TableModelWrapper

“Pipes”

Sortable

TableModel (1)

Actual

TableModel (1)

1

0

0

2

3

1

0

9

2

3

4

5

6

7

8

9

Filterable

TableModel (n)

JTable

Performance and Memory

>
The lookup speed: a direct array access for each table
model wrapper


table.getValueAt
(row, column) calls
tableModel.getValueAt
(
getActualRowAt
(row), column)

>
Memory consumption: one (or two) int array whose
length is the same as the row count


Optional index caching feature to make reverse lookup
to make
getVisualRowAt

method faster


Lazy initialization


The index array is not created until there is sorting


The reverse index array

is not created until
getVisualRowAt

is
called


22

SortableTable

>
SortableTableHeader

to allow click
-
to
-
sort.

23

Filterable related components

>
Different from SortableTable, no FilterableTable

>
Any JTable can be filterable if you set a
FilterableTableModel on to it

>
Other components work with JTable and
FilterableTableModel to make it easy for user to
add/remove filters


AutoFilterTableHeader


QuickTableFilterField (optionally use
Lucene
)


QuickFilterPane


TableCustomFilterEditor

24

If there were one thing to learn …

>
Remember the row index mapping idea and the table
model wrapper design.

25

Case Style: Cell Spanning

26

>
Merge several cells into one big cell

Demo of CellSpanTable

27

Brainstorming

>
Model: store the cell spans

>
View: change how the grid lines are painted

28

CellSpan

>
_row
: Span start row index

>
_column
: Span start column
index

>
_
rowSpan
: The number of
rows that it spans

>
_
columnSpan
: The number
of columns that it spans

CellSpan(1,2,3,4)


row, column, rowSpan, columnSpan

SpanModel

>
Methods:


boolean
isCellSpanOn
()


CellSpan
getCellSpanAt
(int row, int column)

>
Any TableModel can implement this
SpanModel

interface

>
Implementations:


AbstractSpanTableModel


DefaultSpanTableModel
:
addCellSpan
,
removeCellSpan

etc. methods


Example

class
MyModel

extends
AbstractTableModel

implements
SpanModel

{



……. // all other table model methods



CellSpan span;


public CellSpan
getCellSpanAt
(int row, int column) {


// define the span based on the row and column index


return span;


}


public boolean
isCellSpanOn
() {


return true;


}


}

31

Subclassing BasicTableUI

>
BasicCellSpanTableUI

extends BasicTableUI


The
paintGrid

and
paintCells

methods are private


End up overriding paint(g, c) method with many
duplicated code

Subclassing JTable

>
CellSpanTable


Override
getCellRenderer
,
prepareRenderer
,
getCellEditor
,
prepareEditor
,
editCellAt


Override
rowAtPoint
,
columnAtPoint

and
getCellRect


Override
isCellSelected


getCellRenderer


@Override


public TableCellRenderer
getCellRenderer
(int row, int column) {


CellSpan
cellSpan

=
getCellSpanAt
(row, column);


if (
cellSpan

!= null) {


return
super.getCellRenderer
(
cellSpan.getRow
()
,
cellSpan.getColumn
()
);


}


return
super.getCellRenderer
(row, column);


}

34

Other Considerations

>
Caching
CellSpans

at CellSpanTable

>
Caching the painting of
CellSpans

in
BasicCellSpanTableUI

to avoid the cells in the same
CellSpan painted again and again

>
Converting the CellSpan when columns are rearranged
(not all possible)

35

If there were one thing to learn …

>
Store the information along the table model by
implementing a new interface

36

Case Study: Cell Styling

>
Background (solid color or gradient)

>
Foreground

>
Font (font name, style, size)

>
Border

>
Alignment

>
Icon

>
Row stripes/column stripes



37

Demo of CellStyleTable

38

Brainstorming

>
Is cell styling a model concept or a view concept?

39

Brainstorming

>
Is cell styling a model concept or a view concept?


It depends


Row striping is certain a view concept because it has
nothing to do with the table data


However “displaying red text for negative values” is
related to the table data so it is kind of a model concept

40

Brainstorming (Cont.)

>
Providing the
Cellstyle


Using
TableModel



for model related styles


Using
JTable



for non
-
model related styles

41

CellStyle

>
A class define styles mentioned on the previous slide
that has many setters and getters, such as


Color
getForeground
()


void
setForeground
(Color
color
)


Border
getBorder
()


void
setBorder
(Border
border
)

StyleModel

>
Any TableModel can implement the
StyleModel

interface

>
Methods:


boolean
isCellStyleOn
()


CellStyle

getCellStyleAt
(int row, int column)


Subclass JTable
-

CellStyleTable

>
Add
setTableStyleProvider

public interface
TableStyleProvider

{


CellStyle

getCellStyleAt
(
JTable

table, int rowIndex, int
columnIndex
);

}

>
Override
prepareRenderer
/
prepareEditor

methods


Implements Foreground Style

>
prepareRenderer
(renderer, row, column);


Call super to get the
rendererComponent


Gets the
CellStyle
(s) from the
StyleModel
/
TableStyleProvider


If
CellStyle

has a foreground defined, call
rendererComponent.setForeground


Repeat the previous step to cover all styles


BasicTableUI will then paint the
rendererComponent

on the
table cell

>
What will happen if we only do this?


45

Implements Foreground Style

>
prepareRenderer
(renderer, row, column);


Call super to get the
rendererComponent


Gets the
CellStyle
(s) from the
StyleModel
/
TableStyleProvider


If
CellStyle

has a foreground defined, call
rendererComponent.setForeground


Repeat the previous step to cover all styles


BasicTableUI

will then paint the
rendererComponent

on the
table cell

>
What will happen if we only do this?


Because the same renderer is used in a table for
different cells, all those cells will have the same
foreground.


46

Implements Foreground Style: Cont.

>
releaseRendererComponent
(renderer, row, column,
rendererComponent
)


We changed TableUI to always call
releaseRendererComponent

after the
rendererComponent

is painted.


And we reset the foreground to its previous value in this
method


>
We suggest Sun includes this method in JTable

47

If there were one thing to learn …

>
Define cell styling in a consistent way for all the tables
in your application


Define all
CellStyle

instances in one place


You can even create
CellStyle

on fly using
stylesheet

or a
configuration file when application starts.


getCellStyleAt

return the
predefined instance.

48

Showcases

49

Q & A

50

51

David Qiao

JIDE Software, Inc.

david@jidesoft.com