JClass LiveTable

PreviousNextIndex

6

Programming User Interactivity

Cell Traversal  Cell Selection  Resizing Rows and Columns  Table Scrolling

Dragging Rows and Columns  Sorting Columns  Custom Mouse Pointers 

JClass LiveTable makes it easy to allow users to interact with the tables you create. You can control how users can manipulate the table, and how a JClass LiveTable application can control this interaction. The following sections describe the types of user interactivity supported by JClass LiveTable, its default behavior, and how to customize that behavior. Note that programming cell editing behavior is discussed separately in Displaying and Editing Cells, in Chapter 4.


6.1 Cell Traversal

Traversal is the act of moving the current cell indicator from one location to another. A traversal passes through three stages: validating the edited current cell, determining the new current cell location, and entering that cell.

The Traversable property, which is part of the CellStyleModel interface, determines whether or not a cell is traversable. You set this property when you are setting a cell style (for more information about cell styles, please see Cell Styles, in Chapter 2).

6.1.1 Default Cell Traversal

Users can traverse cells by clicking the primary mouse button when the mouse pointer is over a cell. This changes the focus to that cell (a focus rectangle appears around the inside of the cell borders). Users can traverse cells from the keyboard by using the cursor keys (up, down, left, and right) and the Tab key to traverse right and Shift+Tab key to traverse left.

6.1.2 Customizing Cell Traversal

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

Disabling traversal also disables cell editability regardless of whether the cell's data source is editable.

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

  JCCellStyle traverserow = new JCCellStyle
  traverserow.setTraversable(false);
  table.setCellStyle(3, JCTableEnum.ALLCELLS, traverserow);

You can also set the Traversable property for a range of cells specified by a JCCellRange object:

  JCCellRange range = new JCCellRange(2, 3, 2, 8);
  JCCellStyle traverserange = new JCCellStyle;
  traverserange.setTraversable(false);
  table.setCellStyle(range, traverserange);

Use the setTraverseCycle() method, part of the JCTable class, to determine whether the traversal moves to the opposite side when the left, top, right or bottom cell is reached (that is, when the user traverses to the bottom of the table, the next traversal down will bring them to the top of the table). The TraverseCycle property takes a boolean value, and the default is true.

6.1.3 Minimum Cell Visibility

By default, when a user traverses to a cell that is not currently visible, JClass LiveTable scrolls the table to display the entire cell.

The setMinCellVisibility() method sets the minimum amount of a cell made visible when it is entered. When the table scrolls to edit a non-visible cell, the MinCellVisibility property determines the percentage of the cell that is scrolled into view. When MinCellVisibility is set to 100, the entire cell is made visible. When MinCellVisibility is set to 10, only 10% of the cell is made visible. If MinCellVisibility is set to 0, the table will not scroll to reveal the cell.

The value of the MinCellVisibility property also affects the behavior of the makeVisible() methods described in Section 6.3.2, Managing Table Scrolling.

6.1.4 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.

Calling the traverse() method to force cell traversal requires that you define these parameters:

6.1.5 Controlling Interactive Traversal

You can use the TRAVERSE_CELL action in 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 to the next cell. Each event listener is passed an object of type JCTraverseCellEvent.

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

The getColumn() and getRow() methods get 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);
}
  }

6.2 Resizing Rows and Columns

6.2.1 Default Resizing Behavior

JClass LiveTable allows a user to interactively resize a row and/or column (when allowed by AllowCellResize). This action routine alters the PixelHeight property when resizing rows, and the PixelWidth property when resizing columns.

Users can position the mouse pointer over a cell/label border and click-and-drag to resize the row/column. If users position the mouse pointer over the corner of a cell/label, the mouse drag will resize the row and column simultaneously.

6.2.2 Disallowing Cell Resizing

Use the setAllowCellResize() method to control interactive row/column resizing over the entire table. The valid parameters of the AllowCellResize property are:

6.2.3 Controlling Resizing

You can use a JCResizeCellListener (registered with addResizeCellListener(JCResizeCellListener)) 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, with valid stages being BEFORE_RESIZE, RESIZE, and AFTER_RESIZE.

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, which passes objects to JCResizeCellMotionListener during the event. beforeResizeCell(JCResizeCellEvent) 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 resizeCell(JCResizeCellEvent) is available for retrieval (by getNewColumnWidth() or getNewRowHeight()) or changing (by setNewColumnWidth() and setNewRowHeight()), and afterResizeCell() is called with final results.

Note: Interactively resizing cannot exceed the set minimum and maximum cell sizes.

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

  public class MyTable extends Frame implements JCResizeCellListener {
  ...
  public void beforeResizeCell(JCResizeCellEvent ev) {}
  public void resizeCell(JCResizeCellEvent ev) {
    ev.setNewColumnWidth(ev.getNewColumnWidth() / 10 * 10);
  }
  public void afterResizeCell(JCResizeCellEvent ev) {};

To register the above event listener routine, use the following call (where this refers to the class MyTable, which implements the JCResizeCellListener interface):

  table.addResizeCellListener(this);

Resizing all Rows or Columns at Once

You can configure your JClass LiveTable program so that when a user interactively resizes a row or column, all of the other rows or columns in the table resize to the same value. This is achieved by setting the ResizeEven property to true using the following method:

  table.setResizeEven(true);

Setting this property overrides row and column height and width properties, since the rows and columns are all set to the same value as the row and column the user resized.

Resizing Using Only Labels or Cells

As you've seen above, you can control how users can resize cells, rows, columns, and labels. JClass LiveTable also allows you to set the resizing capability so that users can only resize rows and/or columns using the row and column labels.

The setAllowResizeBy() method determines how table rows and columns are resized. Use RESIZE_BY_LABELS to allow resizing only with labels. The mouse pointer will not change to a resize arrow over cell borders in the body of the table.

Using RESIZE_BY_CELLS achieves the opposite, while the default, RESIZE_BY_ALL allows resizing with both cells and labels.


6.3 Table Scrolling

6.3.1 Default Scrolling Behavior

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. JClass LiveTable uses two scrollbar components (one horizontal, one vertical) to implement table scrolling.

JClass LiveTable can also scroll the table when requested by other interactions, such as cell traversal, mouse dragging, or cell selection. Scrolling does not change the location of the current cell.

You can control how and where scrollbars are attached to the component, when they are displayed, and how they behave. The following sections outline programming scrollbar behavior. For information about displaying scrollbars, and setting scrollbar display properties, please refer to Scrollbars, in Chapter 2.

6.3.2 Managing Table Scrolling

Jump Scrolling

You can configure the table to scroll smoothly (by pixel) through the table or to use jump scrolling, which is scrolling the table one whole row or column at a time. This behavior is controlled by calling setJumpScroll() with one of the following parameters:

Using Automatic Scrolling

You can configure the table to scroll automatically whenever a user selects cells or drags the mouse past the edge of the visible table area. To do this, you must call the setAutoScroll() method, specifying one of the following parameters:

Note that automatic scrolling is disabled when no scrollbars are visible and when jump scrolling is enabled.

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 HorizSBDisplay and/or VertSBDisplay to JCTblEnum.SCROLLBAR_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 any of the following four ways.

Mouse Wheel Support

JClass LiveTable has built in mouse wheel support, if mouse wheel support is available in the underlying JDK (JDK 1.4 or higher). By default, a table adds a TableMouseWheelListener which listens for MouseWheelEvents and changes the value of the vertical or horizontal scrollbar, depending on which ones are visible. The vertical scrollbar is used if visible; otherwise, the horizontal scrollbar is used if visible. Mouse wheel support can be disabled by calling removeTableMouseWheelListener(), or the default listener can be replaced by calling addTableMouseWheelListener() with a new MouseWheelListener.

A table scrolls one unit for every click of a scrollbar arrow. This unit value can be set by calling getVertSB() or getHorizSB() and setting the appropriate property on the JScrollBar object that is returned. By default, JClass LiveTable sets the unit to 20 pixels for a horizontal scrollbar and 21 pixels for a vertical scrollbar. If mouse wheel support is enabled, rolling the mouse wheel one click will scroll the table the number of units that your mouse software has been configured to scroll. For example, if this value is set to three and the unit value of the scrollbar is set to 20 pixels, rolling the mouse one click will cause the table to scroll 60 pixels, the equivalent of clicking the corresponding scrollbar arrow three times.

If jumpScroll is set on the scrollbar, scrolling the mouse wheel one click will cause exactly one row or column to be scrolled in the appropriate direction. In this case, one mouse wheel click is exactly the same as clicking once on the corresponding scrollbar arrow.

Tracking Scrollbars

The behavior of scrollbars during tracking can be set by using setHorizSBTrack() for horizontal scrollbars and setVertSBTrack() for vertical scrollbars. Scrolling behavior can be set two ways.

Using JCTableEnum.TRACK_LIVE, the table redisplays while the user scrolls. This type of scrollbar tracking can be resource intensive, particularly with larger tables.

An alternate way of tracking scrollbars is to use JCTableEnum.TRACK_COLUMN_NUMBER for horizontal scrollbar tracking, and JCTableEnum.TRACK_ROW_NUMBER for vertical scrollbar tracking. In these cases, the table does not redisplay until scrollbar tracking is complete, but an indicator appears beside the scrollbar that informs the user where in the table the scrolling has taken them.

When using this kind of tracking, the indicator's appearance is set using setTrackBackground(), setTrackForeground(), and setTrackSize(). The contents of the indicator can either be the row/column number, or the contents of a cell or label.

To display the contents of a cell or label, use setHorizSBTrackRow() and setVertSBTrackColumn() to specify which row or column's data will be used in the scroll tracking indicator, and use JCTableEnum.TRACK_ROW, JCTableEnum.TRACK_COLUMN, or JCTableEnum.LABEL to specify the specific row number (for vertical scrolling), column number (for horizontal scrolling), or label whose data will be used in the indicator.

For example, the following line of code sets the vertical tracking so that it displays the contents of the second column:

  table.setVertSBTrackColumn(1);

6.3.3 Scroll Listener Methods

JClass LiveTable 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(JCScrollListener)) 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 scroll(JCScrollEvent) and afterScroll(JCScrollEvent) scrollbar interface methods to store an internal state:

  public MyClass extends Frame implements JCScrollListener {
  ....
    public void scroll(JCScrollEvent ev) {
    if (ev.getDirection() == TableScrollbar.HORIZONTAL)
    hScrollingActive = true;
    else if (ev.getDirection() == TableScrollbar.VERTICAL)
    vScrollingActive = true;
    }
  public void afterScroll(JCScrollEvent ev) {
    if (ev.getDirection() == TableScrollbar.HORIZONTAL)
    hScrollingActive = false;
    else if (ev.getDirection() == TableScrollbar.VERTICAL)
    vScrollingActive = false;
  }

To register the above event listener routine, use the following call (where (this) refers to the class MyClass, which implements the JCScrollListener interface):

  table.addScrollListener(this);

6.4 Cell Selection

6.4.1 Default Cell Selection

Cell selection is not enabled by default. When cell selection is enabled (see Section 6.4.3, Customizing Cell Selection), the default selection behavior is as follows:

JClass LiveTable 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 supports a number of selection policies, including:

6.4.2 Selection Colors

By default, selected cells and labels display with reversed colors, that is, the background and foreground colors are inverted under selection. When programming the appearance of your table, you can set the colors for selected cells. For more information, please see Cell Selection Colors, in Chapter 2.

6.4.3 Customizing Cell Selection

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 Policy

Example

selection disabled

JCTableEnum.SELECT_NONE

single cell selection

JCTableEnum.SELECT_SINGLE

single range selection

JCTableEnum.SELECT_RANGE

multiple range selection

JCTableEnum.SELECT_MULTIRANGE

When SelectionPolicy is set to JCTableEnum.SELECT_NONE (default), JCSelectEvent events are not posted as a user edits or attempts to select cells. Note that setting this property does not change the selected cell list - this means that if a cell is already selected, then changing this property won't clear the list. As an example, if your selection policy was set to MULTI_RANGE and you selected multiple ranges of cells, a change to RANGE, SINGLE or NONE will not modify the current selection, that is, the current selection will not honour the selection policy.

Selecting Row/Column Labels

By default, when a user clicks on a row or column label, the entire row or column, including the label is highlighted. To change it so that the label is not highlighted with the rest of the cells, set SelectIncludeLabels to false:

  table.setSelectIncludeLabels(false);

6.4.4 Selected Cell List

The SelectedCells property specifies the collection of all currently selected ranges in the table, where each element 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.1

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

The start_column and start_row variables represent the first cell in the range (top-left corner), while the end_column and end_row variables represent the last cell in the 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 anywhere within the table.

6.4.5 Working with Selected Ranges

To get a selected range, use getSelectedCells(). A table's set of selected cells is a collection of JCCellRange instances. This method has the following prototype:

  public Collection getSelectedCells()

Each element of the Collection 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.

Adding to the current selection requires the use of addRowSelection(), addColumnSelection(), or addSelection().

An application can add a selection to the selected cell list by adding the new range to the SelectedCells Collection, as shown by the following code fragment:

  Collection col = table.getSelectedCells();
  col.add(new JCCellRange(1, 1, 3, 3));

6.4.6 Removing Selections

To remove all selections from the table, call clearSelection().

6.4.7 Runtime Selection Control

You can use JCSelectListener (registered with addSelectListener(JCSelectListener)) 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. The getAction() method retrieves one of the following to determine how the cell was selected:

The setCancelled() method determines whether the selection (or unselection) should be allowed (default is false). The Row and Column properties set or retrieve the respective value of the row or column being selected or unselected.

JCSelectListener is called before selection begins (beforeSelect(JCSelectEvent)), after the user's selection is complete (select(JCSelectEvent)) and after all listeners have been notified that the selection is complete (afterSelect(JCSelectEvent)).


6.5 Dragging Rows and Columns

You can configure your JClass LiveTable program to allow users to drag rows and columns to a new position in the table. This feature is implemented using the RowTrigger and ColumnTrigger properties to specify a key-mouse-click combination for dragging a row or column by its label. For example, you can specify that when a user holds the Shift key and clicks on a row label, the user can drag that row to another location in the table. When dragging is enabled, the mouse pointer turns into a hand to indicate that the row or column can be dragged.

To enable users to drag rows and columns by holding down the Shift key and clicking on row or column labels, first call addAction(), with which you define the action's initiation, as well as the action itself.

Here is a code snippet showing the addAction() method in use:

  // Action for dragging columns
  table.addAction(new TableAction(ini, JCTableEnum.COLUMN_DRAG_ACTION));
  // Action for dragging rows
  table.addAction(new TableAction(ini, JCTableEnum.ROW_DRAG_ACTION));

For dragging, the settings for TableAction are JCTableEnum.COLUMN_DRAG_ACTION and JCTableEnum.ROW_DRAG_ACTION.

Dragging a row or column affects only the data view. It does not change the data source.


6.6 Sorting Columns

You can easily program your JClass LiveTable applications and applets to allow users to sort columns in the table. Sorting columns rearranges the rows in the table display, but does not affect the data source of the table. By default, sort behavior does not sort frozen rows set with the setFrozenRows() method (see `Freezing' Rows and Columns, in Chapter 2).

The sortByColumn() method compares objects based on the type of data found in the data source. As such, in some cases, sorting results may vary. For example, using sortByColumn(0, Sort.ASCENDING), where the data used for column 1 are Strings, the String "14" will be considered greater than "110." However, if these same numerical values are represented as integers, 110 will be greater than 14.

Sorting a single column

To sort a single column in the data view, call the sortByColumn() method, specifying the column number to sort, and the direction (Sort.ASCENDING or Sort.DESCENDING):

sortByColumn(2, Sort.DESCENDING);

You can specify that only a particular range of rows is sorted using this variation on the sortByColumn() method with the following construction:

  table.sortByColumn(int col,
   int direction,
   int start_row,
   int end_row)

The following code sorts rows 2 to 18 in column 2 in descending order.

  sortByColumn(1, Sort.DESCENDING, 1, 17);

Sorting Based on Multiple Columns

You can sort columns based on the values of cells in more than one column using the following method construction:

  table.sortByColumn(int col[],
   int direction[])

This method requires that you specify an array of columns on which to base the sorting, and an array of directions in which to sort the columns.

When the sort begins, the rows are sorted based on the first column in the array. If two or more rows contain the same value at the first column, the second column in the array is used to sort the identical values. This process continues until there are no duplicate values in a column, or until the end of the column array is reached.

Consider the following example:

 

Column 0

Column 1

Column 2

Column 3

Row 0

A

20

Z

2

Row 1

G

7

A

4

Row 2

Z

8

B

5

Row 3

B

11

Z

4

Row 4

A

10

C

1

To sort based on the cell values in columns 0, 1, and 3, use the following code:

  int [] columns = {0, 1, 3};
  int [] direction = {Sort.ASCENDING, Sort.ASCENDING, Sort.ASCENDING};
  table.sortByColumn(columns, direction);

In this case, the sort is first based on the data in the rows in column 0. Since column 0 contains two cells with values `A' (Rows 0 and 4), the sort moves to the next column (1) in the array to determine how to sort the two `A' rows. Row 0 at Column 1 has a value of 20 and Row 4 at Column 1 has a value of 10. Since these are sorted in ascending order, the outcome of the sort is:

 

Column 0

Column 1

Column 2

Column 3

Row 4

A

10

C

1

Row 0

A

20

Z

2

Row 3

B

11

Z

4

Row 1

G

7

A

4

Row 2

Z

8

B

5

If there had been duplicate values in column 1, these would have been sorted based on the values in the third column in the array (3).

You can also specify that the sorting operation affect a given range of rows using the following method:

  table.sortByColumn(int col[],
   int direction[],
   int start_row,
   int end_row)

To sort the example above from row 2 to row 4, use the following code:

  int [] columns = {0, 1, 3};
  int [] direction = {Sort.ASCENDING, Sort.ASCENDING, Sort.ASCENDING};
  table.SortByColumn(columns, direction, 2, 4);

6.6.1 Sort by Clicking on a Column Label

With JClass LiveTable you can easily configure your table to sort columns based on a key-mouse-click combination on the column's label. For example, you can specify that when a user holds the Ctrl key and clicks the column label, that column gets sorted in ascending order.

To enable sorting by clicking, call addAction(), with which you define the action's initiation, as well as the action itself. For dragging, the settings for TableAction are JCTableEnum.COLUMN_DRAG_ACTION and JCTableEnum.ROW_DRAG_ACTION.

6.6.2 Resetting the Table after Sorting

To clear all of the changes to the display resulting from column sorting, call the resetSortedRows() method, which resets the display to match the data source.


6.7 Custom Mouse Pointers

When tracking the mouse pointer, JClass LiveTable considers the current settings of AllowCellResize properties. The getAllowCellResize() method retrieves the table's AllowCellResize value. The setAllowCellResize() method sets how an end-user can interactively resize rows/columns; valid values are JCTableEnum.RESIZE_ALL (default), JCTableEnum.RESIZE_NONE, JCTableEnum.RESIZE_COLUMN, and JCTableEnum.RESIZE_ROW.

Disabling Pointer Tracking

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

1Clicking a label selects all of the cells in the row or column, including the label.


PreviousNextIndex