5
Programming User Interaction

Default User Interaction · User Interaction Customization · List Mode

Table Scrolling · Row and Column Resizing · Cell Traversal

Cell Editing · Cell Selection · Mouse Pointers


This chapter describes the user-interaction features of JClass LiveTable Pro: how a user can interact with the table and how an application can control interaction.

Default User Interaction

By default, an end-user can scroll through the table, resize individual rows/columns, traverse from cell to cell, and edit cell values. When enabled, a user can also select cells. The following illustration shows the default user interactions of JClass LiveTable Pro.


JClass LiveTable Pro's Default User Interactions


User Interaction Customization

JClass LiveTable Pro's default user interactions can be modified, depending on the nature of the component. A component generates an event, whose corresponding registered event listener performs the specified action.

An application can be notified as a user interacts with the component by registering event listener routines that are called before, during, and after user interaction. Each event listener routine can affect each interaction in such ways as disallowing or constraining it. See the section for each interaction type for further details on using its event listener.


List Mode

JClass LiveTable Pro allows you to specify that a table displays the entire row as selected when a user clicks on a cell. To do this, set the setMode() property to JCTblEnum.MODE_LIST. When a table is in list display mode, an entire row is selected when a cell is selected. The SelectionPolicy value controls whether users are allowed to select single rows, a range of rows, or multiple ranges of rows.

The default setting for the Mode property is JCTblEnum.MODE_TABLE.


Table Scrolling

When a table is larger than the rows/columns visible on the screen, an end-user can scroll through the table with the mouse or keyboard. To provide this ability, JClass LiveTable Pro uses two scrollbar components (one horizontal, one vertical) for scrolling.

By using the JumpScroll property, you can control the scrolling behavior of each scrollbar. Scrollbars can either scroll smoothly or "jump" scroll in whole row/column increments.

Both the TopRow and LeftColumn properties are updated dynamically as a table is scrolled.

JClass LiveTable Pro also scrolls the table when requested by other interactions, such as cell traversal and cell selection. Scrolling does not change the location of the current cell.

Scrollbars

An application can control how scrollbars are attached to the component, when they are displayed, and the side they are located on. The behavior of the scrollbars can also be controlled.
Scrollbar Attachment
The way scrollbars should be attached to the table depends on the style of table you need for your application. Standard-style tables attach the scrollbars to the cell/label area and move them to match changes to the size of the visible area. List-style tables attach the scrollbars to the table component itself and do not move when the size of the visible area changes--only changes in the component size cause the scrollbars to move and change size.

HorizSBPosition sets how the horizontal scrollbar is attached to the table. Similarly, VertSBPosition sets how the vertical scrollbar is attached to the table. When set to JCTblEnum.SBPOSITION_CELLS (default), the scrollbar is attached to the cell/label viewport (i.e. the cells that are visible). When set to JCTblEnum.SBPOSITION_SIDE, the scrollbar is attached to the side of the table (i.e. the whole of the table).

HorizSBAttachment sets how the end of the horizontal scrollbar is attached to the table. When set to JCTblEnum.ATTACH_CELLS (default), the scrollbar ends at the edge of the visible cells. When set to JCTblEnum.ATTACH_SIDE , the scrollbar ends at the edge of the table.

To specify standard-style table scrollbars:

To specify list-style table scrollbars:

HorizSBOffset and VertSBOffset specify the offset between the scrollbars and the table (default: 6 pixels). This offset usually applies to the space between the scrollbars and the table's cells/labels. However, when the scrollbars are attached to the side of the component, it can also apply to the space between the scrollbars and the side of the component, and only when there is space between the last row/column and the edge of the component.

Scrollbar Display
By default, JClass LiveTable Pro displays each scrollbar only when the table is larger than the number of rows/columns visible on the screen. To display a scrollbar at all times, set HorizSBDisplay and/or VertSBDisplay to JCTblEnum.SBDISPLAY_ALWAYS. Set them to JCTblEnum.SBDISPLAY_NEVER to completely disable the scrollbar display.1
Jump Scrolling
By using the JumpScroll property, you can control the scrolling behavior of each scrollbar. Scrollbars can either scroll smoothly or "jump" scroll in whole row/column increments. When set to JCTblEnum.JUMP_NONE , both scrollbars will scroll smoothly; when set to JCTblEnum.JUMP_ALL , both scrollbars jump scroll. When set to JCTblEnum.JUMP_HORIZONTAL, only the horizontal scrollbar jump scrolls, and when set to JCTblEnum.JUMP_VERTICAL , only the vertical scrollbar jump scrolls. The default value (JCTblEnum.JUMP_VERTICAL ), "jump scrolls" the table one whole row at a time.
Scrollbar Attributes
You can set or retrieve any of the properties of either scrollbar. The following code gets the vertical scrollbar and sets its background color to red:
Component c[] = table.getComponents();
for (int i = 0; i < c.length; i++) {
	if (c[i] == null) continue;
	if (c[i] instanceof TblVertScrollbar) {
		((TblScrollbar)c[i]).setBackground(Color.red);
		break;
	}
}

Programming Scrolling

Disabling Interactive Scrolling

Scrolling can be disabled in one or both directions. Mouse and keyboard scrolling cannot be disabled separately.

Remove the scrollbars from the screen by setting set HorizSBDisplay and/or VertSBDisplay to JCTblEnum.SBDISPLAY_NEVER.

To fully disable any and all scrolling, an application should also ensure that the user cannot select cells or traverse to cells outside the visible area.

Forcing Scrolling

An application can force the table to scroll in the following ways:

Scroll Listener Methods

JClass LiveTable Pro provides a way for your application to be notified when the table is scrolled by either the end-user or the application. The JCScrollListener (registered with addScrollListener()) allows you to define a procedure to be called when the table scrolls; this is useful if your application is drawing into the table. The method is sent an instance of JCScrollEvent.

The example below shows how to use the scrollBegin() and scrollEnd() scrollbar interface methods to store an internal state:

public void scrollBegin(JCScrollEvent ev) {
	if (ev.getDirection() == TblScrollbar.HORIZONTAL) 
		hScrollingActive = true;
	else if (ev.getDirection() == TblScrollbar.VERTICAL) 
		vScrollingActive = true;
}
public void scrollEnd(JCScrollEvent ev) {
	if (ev.getDirection() == TblScrollbar.HORIZONTAL) 
		hScrollingActive = false;
	else if (ev.getDirection() == TblScrollbar.VERTICAL) 
		vScrollingActive = false;
}

To set the event listener for this event, use the following code:

 
     table.addScrollListener(this);


Row and Column Resizing

JClass LiveTable Pro allows a user to interactively resize a row and/or column (when allowed by AllowCellResize). This action routine alters PixelHeight when resizing rows, and PixelWidth when resizing columns. Users cannot resize rows or columns to smaller than 5 pixels.

Disallowing Cell Resizing

Use setAllowCellResize() to control interactive row/column resizing over the entire table. By default, the value of AllowCellResize is set to JCTblEnum.RESIZE_ALL (user resizing of cell permitted). No row/column resizing is allowed when AllowCellResize is set to JCTblEnum.RESIZE_NONE . Only columns may be resized when it is set to JCTblEnum.RESIZE_COLUMN . Only rows may be resized when it is set to JCTblEnum.RESIZE_ROW.

Controlling Resizing

You can use a JCResizeCellListener (registered with addResizeCellListener() ) to control interactive row/column resizing on a case-by-case basis. JCResizeCellEvent is the event posted as a user resizes a row and/or column.

JCResizeCellEvent uses the method getParam(), which retrieves the interactive resize stage. getParam() retrieves one of the following string values:

In addition to getParam(), there are other methods/properties available to JCResizeCellEvent. AllowResize determines whether an interactive resize is allowed (default: true),

The getColumn() method gets the column being resized. The getCurrentColumnWidth() and getCurrentRowHeight() methods get the current column width and the current row height respectively. The NewColumnWidth and NewRowHeight properties can set and retrieve information on the new column width and the new row height respectively.

As a cell is resized by the user, a JCResizeCellEvent is triggered, resizeCellBegin() is sent the initial values (as specified by getCurrentColumnWidth() and getCurrentColumnHeight()). When the user commits the change by releasing the mouse button, the end value from resizeCellEnd() is sent to setNewColumnWidth() and setNewRowHeight().

The following example event listener routine sets the width of any resized column to an increment of 10 pixels:

public void resizeCellBegin(JCResizeCellEvent ev) {}
public void resizeCellEnd(JCResizeCellEvent ev) {
	ev.setNewColumnWidth(ev.getNewColumnWidth() / 10 * 10);
}

To register the above event listener routine, use the following call:

	table.addResizeCellListener(this);


Cell Traversal

Traversal is the act of moving the current cell from one location to another. The Traversable property performs interactive cell traversal. A traversal passes through three stages: validating the edited current cell, determining the new current cell location, and entering that cell. The next illustration shows these stages, and the sequence that event listeners are triggered.

Sequence of cell traversal event listeners

The cell validation and cell entry stages are detailed processes of their own, and are discussed separately.

Note that when users are allowed to select cells (specified with SelectionPolicy), a traversal internally triggers JCSelectEvent event listeners.

Disallowing Cell Traversal

By default, all cells are traversable. To prevent users from traversing to a cell, set Traversable to false. Making a cell non-traversable also prevents it from being traversed to programmatically.

Disabling traversal also disables cell editability regardless of the setting of the Editable property.

The following code fragment sets all cells in row 3 to be non-traversable:

table.setTraversable(3, JCTblEnum.ALLCELLS, false);
	
	table.addTraverseCellListener(this);
}
int val = 0;
public boolean handleEvent(Event event) {
	if (event.id == Event.ACTION_EVENT) {
		val++;
		if (val % 2 == 0) {
			JCVector cells = table.getCells();
			for (int row = 3; row < 6; row++) {
				for (int col = 1; col < 4; col++) {
					((JCVector)cells.elementAt(row)).setElementAt(col, null);
				}
			}
			table.setCells(cells);
		}
		else {
			for (int row = 3; row < 6; row++) {
				for (int col = 1; col < 4; col++) {
					table.setCell(row, col, null);
				}
			}
		}
	}

Minimum Cell Visibility

By default, when a user traverses to a cell that is not currently visible, JClass LiveTable Pro scrolls the table to display the entire cell. You can control how much of the cell is scrolled into view using makeVisible.

setMinCellVisibility() sets the minimum amount of a cell made visible when it is edited. When the table scrolls to edit a non-visible cell, this property determines the percentage of the cell that is scrolled into view. When set to 100, the cell is made completely visible. When set to 10, only 10% of the cell is made visible. If set to 0, the cell will not scroll to be made visible. This property affects the behavior of makeVisible().

Forcing Traversal

An application can force the current cell to traverse to a particular cell by calling Traverse(). If the cell is non-traversable (specified by Traversable), this method returns false.

Controlling Interactive Traversal

You can use TRAVERSE_CELL, the ID variable of JCTraverseCellEvent to control interactive traversal. As a user traverses from one cell to another, this event is posted after a user has committed a cell edit, and before moving the Text component to the next cell. Each event listener is passed an object of type JCTraverseCellEvent.

JCTraverseCellEvent uses the getParam() method to retrieve information on the direction of the traversal. getParam() retrieves one of the following strings indicating the direction of traversal:

In addition to getParam(), there are several other properties available to JCResizeCellEvent. AllowResize determines whether an interactive resize is allowed (default: true). The getColumn() and getRow() methods gets the column and row of the current cell respectively. Finally, the NextColumn and NextRow properties respectively set or retrieve the column and row of the cell to traverse to.

The TRAVERSE_CELL action attempts to traverse to the cell specified by these members. Note that if NextColumn and NextRow reference a non-traversable cell, the traversal attempt will be unsuccessful. The following example code prevents the user from traversing outside of column 0:

public void traverseCell(JCTraverseCellEvent ev) {
	if (ev.getNextColumn() > 0) {
		if (ev.getRow() >= table.getNumRows()) 
			ev.setNextRow(0);
		else 
			ev.setNextRow(ev.getRow() + 1);
		ev.setNextColumn(0);
	}
}


Cell Editing

JClass LiveTable Pro creates and controls a Text component to provide end-users with the ability to edit the value of a cell. By default, a user can edit any cell. When a user traverses to a cell, the Text component is mapped over the cell, containing a copy of the cell value (from the Cells structure). Any change made by the user is written to the Cells structure when the user traverses to another cell.

An application can control the following aspects of interactive cell editing on a cell-by-cell basis: editability, case, multi-line support, and maximum text length. An application can also control attributes and behavior of the current cell itself by programming the table's Text component.

Forcing Edits to Be Assigned to a Cell

To force JClass LiveTable Pro to assign the current edit to a cell, use the following call:
     table.commitEdit(true);

The boolean argument determines whether to hide the Text component. In this example, the edit will be committed and the Text component disappears.

Disallowing Cell Editing
To prevent users from editing a cell value, set Editable to false . Unless traversal has been disabled (specified by Traversable), a user can traverse to a non-editable cell and copy the value using the standard Java copy mechanism.

Note that cells that you want a user to be able to edit must also be traversable (Traversable must be true).

The following example sets row 5 to non-editable (but traversable):

	table.setEditable(4, JCTblEnum.ALLCELLS, false);
	table.addSelectListener(this);
	table.addEnterCellListener(this);
Case Conversion
By default, the text case entered by a user is not changed. Use StringCase to ensure that the text of any cell traversed to or edited by a user is all upper case (JCTblEnum.CASE_UPPER) or all lower case (JCTblEnum.CASE_LOWER). The default value (JCTblEnum.CASE_AS_IS), does not convert the string case.

This property takes effect from the point it is set; it does not convert the case of previously-entered cell values.

Multiple-Line Cells
By default, a user can only enter a single line of text into a cell. To allow a user to enter multiple lines of text, set Multiline to true . By default, Multiline does not let a user enter multiple lines of text into a cell. This property does not affect cell values added or changed by the application. If the cell's value is already multiple lines, a multiple line Text component is displayed when the cell is edited, regardless of the Multiline value.

A Single and Multi-Line cell
Text Length
To limit the number of characters a user can enter in a cell, set MaxLength to the desired maximum number of characters (default: MAXINT). This property does not affect cell values changed with setCell() and setCells(), it only affects cell values entered by the user. Newline characters in multiline cells count as a single character.
Text Component Attributes
You can set or retrieve any of the text properties of the current cell. getText() retrieves the TextComponent ID of the current cell. JCTable.getTextComponent() returns the currently displayed Text component. The following code example sets the background to blue, and the foreground (text) to white for the cells in a table:
	if (table.getTextComponent() != null) {
		table.getTextComponent().setBackground(Color.blue);
		table.getTextComponent().setForeground(Color.white);
	}

Consult your Java documentation for more information on programming TextComponent.

Controlling Editing at Runtime
You can use the ENTER_CELL ID variable of JCEnterCellEvent to control user cell editing at runtime. Triggered by cellTraversal() , ENTER_CELL event listeners are posted before and after completing a traversal from one cell to another.

JCEnterCellEvent uses the getParam() method to retrieve information on the initiating action. getParam() retrieves one of the following strings indicating the direction of traversal:

In addition to getParam(), there are two other methods available to JCEnterCellEvent:getColumn() retrieves the column of the cell being traversed to, while getRow() retrieves the row of the cell being traversed to.

The following event listener routine sets the cell value to the current time when a user traverses to it:

     public void enterCellBegin(JCEnterCellEvent ev) {}


Cell Selection

When enabled, JClass LiveTable Pro allows a user to interactively select one or more ranges of cells. An application can retrieve each range to manipulate the cells within it. An application can also be notified of each user selection to control what and how the user selects cells.

JClass LiveTable Pro supports a number of selection policies, including multirange selection (selecting multiple ranges of cells), single range, single cell, and no selection.

Selection Policy
The SelectionPolicy property controls the amount of selection allowed on the table, both by end-users and by the application. Changing the selection policy affects subsequent selection attempts; it does not affect current selections. The following illustration shows the valid values, and the amount of selection they allow.

Selection policies

When SelectionPolicy is set to JCTblEnum.SELECT_NONE (default), JCSelectEvents are not posted as a user edits or attempts to select cells. Note that setting this property does not change the selected cell list.

Selected Cell List

The SelectedCells property specifies the list of all currently selected ranges in the table, where each element of the vector is an instance of a JCCellRange. SelectedCells is updated dynamically as a user selects cells. It is also updated when an application programmatically selects or deselects cells. Labels cannot be part of a selected range. 2

Each range in the selected cell list is a JCCellRange structure. Its variables include:

start_column is the column of the first cell in range (top-left corner), while start_row is the first cell in range (top-left corner). end_column is the column of the last cell in a range (top-left corner), and end_row is the row of the last cell in range (bottom-right corner).

All members of the JCCellRange structure can be a row and column index. end_row and end_column can also be set to MAXINT , which specifies all of the cells in a row or column. Because the user can make a selection at any point and in any direction within a table, the start point is not necessarily the top-left corner of the range--it may be any of the four corners of a range.

The following example sets two selected ranges:

	table.setSelectionPolicy(JCTblEnum.SELECT_MULTIRANGE);
	JCCellRange ranges[] = new JCCellRange[2];
	ranges[0] = new JCCellRange(0, 0, 4, 2);
	ranges[1] = new JCCellRange(7, 1, 7, 4);
	JCVector v = new JCVector(ranges);
	table.setSelectedCells(v);

Selection Colors

You can customize the colors used to indicate selected cells by setting the setSelectedBackground() and setSelectedForeground().

setSelectedBackground() determines the background color of selected cells, while setSelectedForeground() determines the foreground color of selected cells. By default, the default value for setSelectedBackground() is the cell's foreground color, while the default value for setSelectedForeground() is the cell's background color. When setSelectedBackground() is set to null, selected cells appear identical to unselected cells. When setSelectedForeground() is set to null and setSelectedBackground() is not null, the foreground of selected cells is the same as the foreground colors defined for the cells. This value is ignored when setSelectedBackground() is set to null.

Working with Selected Ranges

To get a selected range, allocate a JCCellRange structure and call getSelectedRange(). This method has the following prototype:
public boolean getSelectedRange(int pos,
                                        JCCellRange range)

SelectedRange retrieves a currently-selected range from the SelectedCellList , and it can take the following parameters:

range is rationalized to read from top to bottom and from left to right, and special values such as MAXINT are converted to valid range values. SelectedRange returns false if no cells are selected, or if any argument is invalid.

The following example gets each selected range (assuming that selection policy is JCTblEnum.SELECT_MULTIRANGE):

 
	int i = 0;
	JCCellRange r = new JCCellRange();
	while (table.getSelectedRange(i++, r)) {
		System.out.println("Range " + i + " is 
		(" + r.start_row + "," + r.start_column + ") to 
		(" + r.end_row + "," + r.end_column + ")");
	}

To determine whether a particular cell is selected, and retrieve the range if it is, call getSelectedCells(). This method has the following prototype:

 
     public Vector getSelectedCells()

Each element of the Vector is an instance of a JCCellRange. This value is updated dynamically as a user selects cells. The selection policy controls the amount of selection allowed on the table, both by users and by the application. Users can select in any direction, so start_row and/or start_column may be greater than end_row and/or end_column . When a user clicks a row/column label to select an entire row or column, end_row or end_column is set to MAXINT.

Forcing Selection
An application can add a selection to the selected cell list by adding the new range to the SelectedCells Vector, as shown by the following code fragment:
		JCCellRange nr = new JCCellRange(8, 1, 8, 4);
		Vector ve = table.getSelectedCells();
		ve.addElement(nr);
		table.setSelectedCells(ve);
		
		return true;
	}
	return super.handleEvent(event);
Removing Selections
To remove all selections from the table, call setSelectedCells(null).
Runtime Selection Control
You can use JCSelectListener (registered with addSelectListener() ) to control interactive cell selection at each stage, on a case-by-case basis. JCSelectEvent has a number of methods and properties, enabling the programmer to modify the JCSelectEvent. One of these, getParam() , is used to retrieve information on the initiating action. getParam() retrieves one of the following strings which determines how the cell was selected (if no selection is possible on a label):

The getAllowSelection() method determines whether the selection (or unselection) should be allowed (default: true). The Row and Column properties set or retrieve the respective value of the row or column being selected or unselected. The getEvent() method gets the event that initiated the action. The getStage() method retrieves the selection stage (either INITIAL or EXTEND), while getStateChange() returns the state change type generated by the event (either SELECTED or DESELECTED).

JCSelectListener is called before selection begins (selectBegin() ), and after a selection has finished (selectEnd()).

The following event listener routine constrains selection to the column where it started:

public void selectBegin(JCSelectEvent ev) {
	if (ev.getStage() == JCSelectEvent.INITIAL) {
		 save_column = ev.getColumn();
	}
	else if (ev.getStage() == JCSelectEvent.EXTEND) {
		if (ev.getColumn() != save_column) 
			ev.setAllowSelection(false);
	}
}
public void selectEnd(JCSelectEvent ev) {}
public boolean handleEvent(Event event) {
	if (event.id == Event.ACTION_EVENT) {

To select an entire row or column, set the Row or Column properties of JCSelectEvent to JCTblEnum.ALL. Note that you cannot set a RowLabel or ColumnLabel in this manner.


Mouse Pointers

JClass LiveTable Pro uses the twelve standard platform-independent cursors that can be specified for an AWT Frame. The cursor tracks the mouse pointer as a user moves over and interacts with the component. When the pointer is over cells or labels, it changes shape to provide users with a visual cue as to the interaction available at that point. See your Java documentation for details on cursor types.

When tracking the mouse pointer, JClass LiveTable Pro considers the current settings of the Traversable and AllowCellResize properties.

Disabling Pointer Tracking
To use an application-defined mouse pointer over the entire component, set TrackCursor to false; JClass LiveTable Pro will not track the position of the mouse over the component. By default, TrackCursor is set to true.


1 Although scrollbars are removed, a user can still scroll with the keyboard. See "Disabling Interactive Scrolling" for complete information on disabling interactive scrolling.

2 Clicking on a label selects all of the cells in the row or column, not including the label.