6
JClass LiveTable Pro Programming

Components in Cells/Labels · Cell/Label Value Validation · Table Sizing and Resizing

Multiple Tables with Common Cell Values · Performance Improvement

Using an External Data File · Live Data Updating


This chapter covers topics that programmers of advanced JClass LiveTable Pro applications will find useful. It assumes that you are already familiar with JClass LiveTable Pro.


Components in Cells/Labels

Any cell or label can contain any Java AWT (or JClass BWT) component as well as strings, JCStrings and images. Components in cells/labels are fully functional--you can program their attributes and handle user interaction with them. The table manages the component's sizing and geometry.

Setting components in cells

Components in cells/labels are useful for providing menus or buttons within a table.

Components can be located individually in cells, or a class of components can be placed in an entire row or column. In the latter case, sufficient components are created only as necessary as the table is scrolled.

Components in a Table

Adding a Component

You can place a component in a cell by using setComponent().

The following example uses setComponent() to place a component in a series of cells. Buttons are put in every cell in the first column, and the labels are put in every cell in the third column.

	table.setComponent(JCTblEnum.ALLCELLS, 0, new Button());
	table.setComponent(JCTblEnum.ALLCELLS, 2, new Label());

Variable Rows/Columns

When a component is set in a variable row or variable width column, JClass LiveTable Pro will resize the row/column to fit the component's preferred size.

Hiding a component

To hide a component (remove a component from the table temporarily), call setComponent() with a null component.

Determining Component Location

Use getPosition() when your application needs to determine the cell/label location containing a given component. This is useful when the same event listener routine is called by several cloned components, as seen in the following code fragment:
	JCCellPosition pos = table.getPosition(myComponent, null);
	button.setLabel(table.getCell(pos.row, pos.column).toString());

Create Component Listener

To listen for an event generated by a component contained with a table, use a JCCreateComponentListener (registered with addCreateComponentListener()). JCCreateComponentListener must be used to create a component when you have set a component for a range of cells (e.g. an entire column). You can also use it to set attributes for each component when it is created. JCCreateComponentListener is passed an instance of type JCCreateComponentEvent.

A JCCreateComponentListener can change the component member. This allows new items to be created as needed, as demonstrated by the creation and display of a Button in the following code fragment:

public void createComponent(JCCreateComponentEvent ev) {
	if (ev.getColumn() == 0) 
		ev.setComponent(new Button());
	else if (ev.getColumn() == 2) 
		ev.setComponent(new Label());
}
public void displayComponent(JCDisplayComponentEvent ev) {
	if (ev.getColumn() == 0) {
		Button button = (Button)ev.getComponent();
}

Display Component Event Listener

To set the attributes on a component before it is displayed, use a JCDisplayComponentListener (registered with addDisplayComponentListener()). The JCDisplayComponentListener is passed an instance of an object of type JCDisplayComponentEvent.

To register a JCDisplayComponentListener, use addDisplayComponentListener() , as shown in the following line of code:

	table.addDisplayComponentListener(this);

Components in HTML Files

JClass LiveTable Pro can create components specified in property files using the specified class. For example, the following HTML file fragment creates Button components for all of the cells in a column:
<APPLET>
...
<PARAM NAME=componentList value="(allcells 4 Button)">
...
</APPLET>

To specify a third-party component in an HTML file, use its full class name as in the following HTML file fragment:

<APPLET>
...
<PARAM NAME=componentList value="(1 1 jclass.table.JCTable)">
...
</APPLET>

Cell/Label Value Validation

Overview

JClass LiveTable Pro can be set to intercept and validate cell and label values before writing them to the table's cell and label values structures. Edited text is validated against a "data type" you specify for the cell/label. The validation method parses the edited cell/label value, and changes JCValidateCell's setAllowValueChange method to false if the value does not conform to the data type.

Cell/Label Data Type

Use the DataType property of JCValidateCellEvent to set the data type of cells and labels. This sets the data type of a cell/label value. When set, this property affects cell and/or label value changes from that point on. Before committing a changed cell/label value, the table additionally posts a JCValidateCellEvent if a JCValidateCellListener has been registered. The default data type, TYPE_STRING, causes no validation to be performed (anything is a valid String). The following lists the available data types:

Property Value Data Type

JCTblEnum.TYPE_STRING

Any text string

JCTblEnum.TYPE_DOUBLE

Double-precision value

JCTblEnum.TYPE_INTEGER

Integer value

JCTblEnum.TYPE_FLOAT

Floating-point value

JCTblEnum.TYPE_BOOLEAN

Any Boolean value

Validation Policy

The ValidatePolicy property determines the type of editing that triggers validation (specified by DataType). By default, validation is turned off. When set to VALIDATE_ALWAYS, any change to cells or labels is validated, whether made by a user, or by the application. When set to VALIDATE_NEVER, no validation is performed. When set to VALIDATE_SET , only changes made by an application are validated. The code example below sets the validation policy to VALIDATE_USER_EDIT, which means validation is performed only when the user enters data. The following code fragment demonstrates how to set ValidatePolicy so that only validates data entered by a user, and then how to register it with JCValidateCellListener by using addValidateCellListener.
	table.setValidatePolicy(JCTblEnum.VALIDATE_USER_EDIT);
	table.addValidateCellListener(this);

Numeric validation (through the DataType and ValidationPolicy properties) is performed using Java routines like Double.valueOf(string).doubleValue(). These routines can be problematic, allowing trailing non-numeric characters. If this is a concern, add a JCValidateCellListener to validate the data.

Validate Cell Listener

The ValidateCellListener is used by data validation methods. This can be used to capture a failed data type validation and attempt to get more information from the user.

The two listener methods are validateCellBegin or validateCellEnd. The getChanged() method is used to indicate whether the user has attempted to change the cell. The Value property can be modified to point to a new value for the cell. The setAllowValueChange() method can be set to false to reject the data. The following example validates both integer and floating-point data using two different techniques:

public void validateCellBegin(JCValidateCellEvent ev) {}
public void validateCellEnd(JCValidateCellEvent ev) {
	if (ev.getColumn() == 1) {
		Integer in = (Integer)ev.getValue();
		if (in.intValue() > 60) {
			System.out.println("Integer too large");
			ev.setAllowValueChange(false);
		}
	}
	else if (ev.getColumn() == 2) {
		Double db = (Double)ev.getValue();
		if (db.doubleValue() > 60.0) {
			System.out.println("Double too large - set to 60.0");
			ev.setValue(new Double(60.0));
		}
	}
}


Table Sizing and Resizing

A table determines its size based on the visible rows and columns when its peer is created, or when it is added to a parent whose peer exists. For more information on peers, consult your Java documentation.

Expose and Resize Listener

An application can find out when the table component is exposed by specifying a routine using the JCPaintListener. You can use event listeners to draw onto the table image using AWT procedures.


Multiple Tables with Common Cell Values

Sometimes an application will want to create several table components that share the same Cells Vector structure. This structure serves as a central data store for all the tables.

To accomplish this, set the values in one table, get the Cells Vector from it using getCells(), and then set the values in the other table using setCells().

If users should be able to edit the cells in any of the tables, you should use ValidateCell to capture cell editing and update both the corresponding cell value in the other table.

All of this is shown by the following example:

import jclass.table.JCTable;
import jclass.table.JCTblEnum;
import jclass.table.JCValidateCellEvent;
import jclass.table.JCValidateCellListener;
import jclass.util.JCVector;
import java.awt.*;
import java.applet.Applet;
public class s6c extends Applet implements JCValidateCellListener {
JCTable table1;
JCTable table2;
String cells[][] = {
	{"James Q. Doohan","1701 Planetia Blvd.\nAnytown, U.S.A.",
	 "","President","$245,000"},
	{"John F. Kricfalusi","983 Nickelodeon Street\nAnytown, U.S.A.",
	 "(999) 555-9876","Animator","$1,000"},
	{"Marc Lenard","6 Gene Crescent\nAnytown, U.S.A.",
	 "(999) 555-1212","Telemarketer","$10 / hr."},
	{"Hikaru I. Takei","134 Adelaide Street E.\nSuite 204\nAnytown, U.S.A."
	 ,"(999) 594-1026","OEM Sales","50%"},
	{"Melissa A. Truman","475 Woodview Line\nAnytown, U.S.A.",
	 "(999) 555-9030","Technical Writer","$5,250"},
	{"Stephanie L. Truman","388 Appleby Road\nAnytown, U.S.A.",
	 "(999) 555-2642","System Analyst","$85,750"},
	{"Bill West Jr","1001 Spumco Way\nAnytown, U.S.A.",
	 "(999) 555-9966","Announcer","$17,500"},
	{"Stephen L. Truman","388 Appleby Road\nAnytown, U.S.A.",
	 "(999) 555-2642","Motivational Speaker","$250,000"},
	{"Bill West","1001 Spumco Way\nAnytown, U.S.A.",
	 "(999) 555-9966","Father Figure","$7,500"}
};
public void init() {
	setLayout(new GridLayout(2,1));
	table1 = new JCTable();
	table2 = new JCTable();
	add(table1);
	add(table2);
	table1.setNumRows(9);
	table1.setNumColumns(5);
	table2.setNumRows(9);
	table2.setNumColumns(5);
	JCVector cellsV = new JCVector(cells.length);
	for (int i = 0; i < cells.length; i++) 
		cellsV.setElementAt(i, new JCVector(cells[i]));
	table1.setCells(cellsV);
	table2.setCells(cellsV);
	table1.setValidatePolicy(JCTblEnum.VALIDATE_USER_EDIT);
	table2.setValidatePolicy(JCTblEnum.VALIDATE_USER_EDIT);
	table1.addValidateCellListener(this);
	table2.addValidateCellListener(this);
}
public void validateCellBegin(JCValidateCellEvent ev) {}
public void validateCellEnd(JCValidateCellEvent ev) {
	if (ev.getSource() == table1) 
		table2.paint(ev.getRow(), ev.getColumn());
	else
		table1.paint(ev.getRow(), ev.getColumn());
}
}


Performance Improvement

When a table contains a large amount of data, or its attributes change frequently over its life, its performance can degrade. This section describes how to improve table performance.

The stocks demo demonstrates many of these methods for many JClass LiveTable Pro tasks (including adding rows, columns and values).

General Performance

Interactive Performance

If a large table has few traversable cells, traversal performance can be improved by setting Traversable to false and customizing traversal using a JCTraverseCellListener.

Display Performance

Cell Values Handling


Using an External Data File

There are some cases when it is more desirable to have the properties located outside of the source code of the Java program. The chief advantage of this method is that it allows the properties to be changed using a simple editing program. This saves having to recompile the Java program whenever properties need to be altered. This is usually accomplished by loading the values from the HTML page the applet resides in, using data contained within a number of the <PARAM NAME= ... VALUE= ...> tags.

In some cases it is more desirable to load the data from an external source containing no HTML elements or tags. One advantage is that the data can easily be altered without having to know HTML, and that changes made to this file cannot adversely affect the way information is laid out on a Web page either through accident or omission.

Using this method, you can manipulate cell values but not any table properties.

The following code listing is for a program that loads the cell values from an external data file.

1.	import jclass.table.JCTable;
2.	import jclass.table.JCTblEnum;
3.	import jclass.util.JCVector;
4.	import jclass.util.JCFile;
5.	import java.awt.*;
6.	import java.applet.Applet;
7.	public class table6 extends Applet {
8.	static String file = "table6.dat";
9.	public void init() {
10.		setLayout(new GridLayout(1,1));
11.		// Create table
12.		JCTable table = new JCTable();
13.		// Set table size in terms of rows and columns
14.		table.setNumRows(7);
15.		table.setNumColumns(5);
16.		// Read values for cells from file
17.		JCVector cells = JCFile.read(this, file, ',', true);
18.		// Set values for cells
19.		table.setCells(cells);
20.		// Set cell colors
21.		table.setBackground(JCTblEnum.ALL, JCTblEnum.ALL, Color.yellow);
22.		table.setForeground(JCTblEnum.ALL, JCTblEnum.ALL, Color.blue);
23.		// Set cell sizes
24.		table.setPixelWidth(JCTblEnum.ALL, JCTblEnum.VARIABLE);
25.		table.setPixelHeight(JCTblEnum.ALL, JCTblEnum.VARIABLE);
26.		add(table);
27.		}
28.	}

As you can see from the source code, table6.java shares much of the code with table1.java (see Figure 1), but whereas table1.java contains its cell values within the program, table6.java retrieves its cell values from table6.dat.

Line 8 specifies the location (URL) of the data file containing the table data. 1 Line 17 specifies the characters that are used as delimiters within the data file. Lines 17 contains the code that retrieves the values of the table's cells from the URL using JCFile.read.

The following code listing displays the HTML code for table6.dat, whose values are loaded into the cells in table6.java.

James Q. Doohan,1701 Planetia Blvd. Anytown U.S.A.,,President,$245,000
John F. Kricfalusi,983 Nickelodeon Street Anytown U.S.A.,(999) 555-9876,Animator,$1,000
Marc Lenard,6 Gene Crescent Anytown U.S.A.,(999) 555-1212,Telemarketer,$10 / hr.
Hikaru I. Takei,134 Adelaide Street E. Suite 204 Anytown U.S.A.,(999)594-1026,OEM Sales,50%
Melissa A. Truman,475 Woodview Line Anytown U.S.A.,(999) 555-9030,Technical Writer,$5,250
Stephanie L. Truman,388 Appleby Road Anytown U.S.A.,(999) 555-2642,System Analyst,$85,750
Bill West,1001 Spumco Way Anytown U.S.A.,(999) 555-9966,Announcer,$17,500

table6.dat - The data retrieved by table6.java

There are advantages and disadvantages to using this method to load data. One advantage is the cell data can easily be changed using a simple editing program, whereas table1.java would have to be edited and recompiled to reflect any changes. A disadvantage of using this method is the act of retrieving the data from another file makes table6.java run more slowly than table1.java.


Live Data Updating

It is possible to update data within a JClass LiveTable Pro table using sockets or any other live data source. A small amount of code must be written to retrieve the data and update the JClass LiveTable Pro instance. The following code example provides an example of this:
// Set data types for the columns
        table.setDatatype(JCTblEnum.ALLCELLS, 1, JCTblEnum.TYPE_DOUBLE);
        table.setDatatype(JCTblEnum.ALLCELLS, 2, JCTblEnum.TYPE_DOUBLE);
        table.setDatatype(JCTblEnum.ALLCELLS, 3, JCTblEnum.TYPE_DOUBLE);
        table.setDatatype(JCTblEnum.ALLCELLS, 4, JCTblEnum.TYPE_INTEGER);
        // Read the data from the file.  Data is comma-separated.
        JCVector values = JCFile.read(this, "american.dat", ',', false);
        // Convert the data to the data types in the table
        table.convert(values, 0, 0);
        // Add the data to the table.
        table.setCells(values);
        // Set the number of rows in the table.
        table.setNumRows(values.size());

This code is used within the javaexpo demonstration files, which derives its "live" cell values from an external data file.

While there are no socket data retrieval routines included in JClass LiveTable Pro, it is possible to use a JCCellValueListener to allow an application to retrieve data in a cell-by-cell basis.


1 You may have to alter the source code in table6.java to point to the directory containing table2.dat on your system.