JClass HIGrid

PreviousNextIndex

4

Displaying and Editing Cells

Overview  Default Cell Rendering and Editing

Rendering Cells  Editing Cells  The JCCellInfo Interface


4.1 Overview

JClass HiGrid offers a flexible way to display and edit any type of data contained in its cells. The following sections explain the techniques for displaying and editing cells in your programs.

In order to display a cell, JClass HiGrid has to know what type of data renderer is associated with the cell so it knows how to paint that data into the cell area. Similarly, in order for users to edit the cell values, HiGrid has to know what editor to return for that data type.

These operations are performed using the classes in the JClass cell package, which is structured as follows:

JClass Cell Package

Contents

com.klg.jclass.cell

Contains editor/renderer interfaces and support classes, including these interfaces:

 

JCCellEditor: Used to define an editor.

 

JCCellRenderer: The common and basic interface for renderers.

 

JCComponentCellRenderer: Allows the creation of renderers that are based on JComponent.

 

JCLightCellRenderer: Allows the creation of renderers based on direct drawing.

com.klg.jclass.cell.
editors

Contains editors for common data types.

Please see Section 4.4.1, Default Cell Editors, for details.

com.klg.jclass.cell.
renderers

Contains renderers for common data types.

Please see Section 4.3.1, JClass Cell Renderers, for details.

com.klg.jclass.cell.
validate

Contains data validation interfaces and support classes.

This JClass cell package is generic; renderers and editors written for JClass HiGrid will work with other JClass products. In addition, JClass Field components can work as renderers and editors within HiGrid, allowing very lightweight operation.

JClass HiGrid has been designed to identify the type of data being retrieved from the data source and to provide the appropriate cell renderer and cell editor for that data type. Often, however, you will want to control the way data in a particular area of the grid is rendered, or assign a specific type of editor for that data. An example of this is rendering String data in multiple lines and using javax.swing.JTextArea as the editor, rather than rendering and editing single-line Strings.

The following sections describe the techniques for rendering and editing cells by beginning with the easiest default methods, followed by detailed explanations for setting specific renderers and editors, mapping renderers and editors to a particular data type, and creating your own renderers and editors.


4.2 Default Cell Rendering and Editing

Basic Editors and Renderers

When the grid draws itself, it accesses the data source and attempts to paint the contents of each cell. In doing so, it:

  1. Looks for a renderer and editor for that data in its list of default editors and renderers.
  2. Assigns a renderer and an editor to each cell type. You can override this default mapping if you wish.

The following table lists the cell renderers and editors for common data types included with JClass HiGrid, which are found in the com.klg.jclass.cell.renderers and com.klg.jclass.cell.editors packages, respectively. When going through the above steps, JClass HiGrid uses these default mappings.

Data Type

Renderer

Editor

Big Decimal

JCStringCellRenderer

JCBigDecimalCellEditor

Boolean

JCCheckboxCellRenderer

JCCheckboxEditor

Byte

JCStringCellRenderer

JCByteCellEditor

Byte Array (for Images)

JCRawImageCellRenderer

JCImageCellEditor

Double

JCStringCellRenderer

JCDoubleCellEditor

Float

JCStringCellRenderer

JCFloatCellEditor

Integer

JCStringCellRenderer

JCIntegerCellEditor

Long

JCStringCellRenderer

JCLongCellEditor

Object

JCStringCellRenderer

JCStringCellEditor

Short

JCStringCellRenderer

JCShortCellEditor

SQL Date

JCStringCellRenderer

JCSqlDateCellEditor

SQL Time

JCStringCellRenderer

JCSqlTimeCellEditor

SQL Timestamp

JCStringCellRenderer

JCSqlTimestampCellEditor

String

JCStringCellRenderer

JCStringCellEditor

Util Date

JCStringCellRenderer

JCDateCellEditor

Although these editors and renderers are included with JClass HiGrid, you might find that you need more control over the way data is displayed and edited than simply relying on these defaults. The following sections explain cell rendering and cell editing in detail.


4.3 Rendering Cells

Cell rendering is simply the way in which data is drawn into a cell. JClass HiGrid includes renderers that you can use in your grid. Additionally, two rendering models, JCLightCellRenderer and JCComponentCellRenderer, are provided if you want to create your own renderer. Each model caters to different rendering needs.

More information about included renderers are found in the next section, and information about the two rendering models on which you can base customized renderers is found in Section 4.3.3, Creating your own Cell Renderers.

4.3.1 JClass Cell Renderers

As shown in the table above, JClass HiGrid maps standard data types to specific renderers when the program does not specify a renderer for that data type. This means that most grids are easily rendered without any special coding. The renderers are internally assigned.

Name

Data Type

Description

JCCheckBoxCellRenderer

Boolean

Defines a JCComponentCellRenderer object that paints Boolean objects in a grid cell using Swing's JCheckBox.

JCComboBoxCellRenderer

integer

Defines a JCComponentCellRenderer that paints integer objects in a grid using Swing's JComboBox.

JCImageCellRenderer

image

Defines a JCLightCellRenderer object that paints Image objects in a grid cell.

JCLabelCellRenderer

String

Defines a JCLabelCellRenderer object that uses Swing's JLabel to render cell contents

JCRawImageCellRenderer

image

Defines a JCLightCellRenderer object that paints unconverted Image objects in a grid cell (extends JCScaledImageCellRenderer)

JCScaledImageCellRenderer

image

Defines a JCLightCellRenderer object that paints scaled Image objects in a grid cell.

JCStringCellRenderer

String, Boolean, double, float, integer, object.

Defines a JCLightCellRenderer object that can draw Strings.

JCWordWrapCellRenderer

String

Defines word-wrapping logic for multi-line display of Strings in cells.

The default mappings and these special renderer classes should provide rendering for most data types. Few programmers work under ideal conditions, however, and you may need to extend the capability of these renderers. JClass HiGrid includes ways for you to customize cell rendering, as described in Section 4.3.3, Creating your own Cell Renderers.

4.3.2 Mapping a Data Type to a Cell Renderer

Because there are many different data types within a row, JClass HiGrid creates a mapping between data types and cell renderers. The mapping takes a data type and associates it with a cell renderer; whenever the container encounters that type of data, it uses the mapped JCCellRenderer. This mapping is performed automatically for standard JDBC data types.

Mapping a JCCellRenderer object to a data type takes the following construction, where cellType is the cell renderer and thisCell is the current cell:

thisCell.CellFormat.setCellRendererName(String cellType);

Normally, you would use these mappings in a construction that would test for the presence of the renderer you specify, and throw an exception if the class was not found.

It is possible to use a new feature of the com.klg.jclass.cell package, called the EditorRendererRegistry, to associate a data type with an editor and a renderer. Imagine a case where you have a column of Boolean quantities. You wish to allow your users to edit a cell by typing a zero or a one, but you wish to display the result in a checkbox. The following code associates the desired editor and renderer with the underlying data type:

EditorRendererRegistry.getCentralRegistry().addClass(
"java.lang.Integer",
null,

"com.klg.jclass.cell.editors.JCIntegerCellEditor",
"com.klg.jclass.cell.renderers.JCCheckBoxCellRenderer");

JClass HiGrid will now use these editors/renderers for integer types.

Note however that a mapping via the central registry is global, in the sense that it will be used by all the JClass components in your application that use editors and renderers.

See the JCLASS_HOME/examples/higrid/data example for changing editors and renderers on a per-column basis. To see how to override the default associations between data types and editors/renderers, see EditorRendererExample in the JCLASS_HOME/examples/higrid/visual directory.

4.3.3 Creating your own Cell Renderers

Naturally, the renderer classes provided with JClass HiGrid will not meet every programmer's specific needs. However, they can be convenient as bases for creating your own renderer objects by subclassing the original classes. If you want to create your own renderer classes, you can build your own renderer from scratch. Both techniques are discussed below.

Subclassing the Default Renderers

A simple way to create your own renderer objects is to subclass one of the renderers provided with JClass HiGrid. For example, CurrencyRenderer.java is an example of subclassing from the JCStringCellRenderer in the com.klg.jclass.cell.renderers package:

import com.klg.jclass.cell.renderers.JCStringCellRenderer;
import com.klg.jclass.cell.JCCellInfo;

import java.awt.Graphics;

public class CurrencyRenderer extends JCStringCellRenderer {

public void draw(Graphics gc, JCCellInfo cellInfo, Object o, boolean selected) {
  if (o instanceof Double) {
    double d = ((Double)o).doubleValue();
    o = formatLabel(d, 2);
  }
  super.draw(gc, cellInfo, o, selected);
}

Creating a Drawing-based Cell Renderer with JCLightCellRenderer

One way JClass HiGrid lets you write your own cell renderer is with JCLightCellRenderer. This model is used for drawing directly into a cell, which is ideal for custom painting and rendering text.

To create a drawing-based renderer object of your own, you must implement com.klg.jclass.cell.JCLightCellRenderer:

public interface JCLightCellRenderer {
public void draw(Graphics gc, JCCellInfo cellInfo, Object o, boolean
         selected);

public Dimension getPreferredSize(Graphics gc, JCCellInfo cellInfo,
         Object o);

}

The JCLightCellRenderer interface requires that you create two methods:

The following code, TriangleCellRenderer.java, draws a triangle into the cell area:

import java.awt.Polygon;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import com.klg.jclass.cell.JCCellInfo;
import com.klg.jclass.cell.JCLightCellRenderer;

public class TriangleCellRenderer implements JCLightCellRenderer {

public void draw(Graphics gc, JCCellInfo cellInfo, Object o, boolean selected) {
  Polygon p = makePolygon(o);
  gc.setColor(selected ? cellInfo.getSelectedForeground():cellInfo.getForeground());
  gc.fillPolygon(p);
}

public Dimension getPreferredSize(Graphics gc, JCCellInfo cellInfo, Object o) {
  // Make a polygon from the object
  Polygon p = makePolygon(o);
  // Return no size if no polygon was created
  if (p == null) {
    return new Dimension(0,0);
  }
  // Bounds of the polygon determine size
  Rectangle r = p.getBoundingBox();
  return new Dimension(r.x+r.width,r.y+r.height);
}

private Polygon makePolygon(Object o) {
  if (o == null) return null;
  if (o instanceof Number) {
    return makePolygon(((Number)o).intValue());
  }
  else if (o instanceof Polygon) {
    return (Polygon)o;
  }
  return null;
}


public Polygon makePolygon(int s) {
  Polygon p = new Polygon();
  p.addPoint(0,0);
  p.addPoint(0,s);
  p.addPoint(s,0);
  return p;
}
}

The above program creates a triangle renderer object that can handle both Integer and Polygon objects.

As required by JCCellRenderer, the program contains a draw() method in the lines:

public void draw(Graphics gc, JCCellInfocellInfo, Object o boolean
        selected) {

Polygon p = makePolygon(o);
gc.getColor(selected ? cellInfo.getSelectedForeground():
        cellInfo.getForeground());

gc.fillPolygon(p);
}

The draw() method renders the object o by making it into a polygon and drawing the polygon using the gc provided. The grid, as the container, automatically translates and clips the gc, draws in the background of the cell, and sets the foreground color.

The parameter cellInfo can be used to retrieve other cell property information through the JCCellInfo interface (see Section 4.5, The JCCellInfo Interface).

The second required method, getPreferredSize(), is provided in the lines:

  public Dimension getPreferredSize(Grahpics gc, JCCellInfo cellInfo,
                     Object o) {

  Polygon p = makePolygon(o);
  if (p == null) {
    return new Dimension(0,0);
  }
  Rectangle r = p.getBoundingBox();
  return new Dimension(r.x+r.width,r.y+r.height);
  }

Here, the object is used to create a polygon (using a local method called makePolygon()). If it doesn't create a polygon from the object, the object is deemed to have no size (0,0) and will not be displayed by the renderer. If a polygon was created from the object, the polygon's bounds determine the size of the rectangle in the drawing area of the cell. The size returned is only a suggestion; control of the cell size can be overridden by the grid container.

Creating a Component-based Cell Renderer with JCComponentCellRenderer

While JCLightCellRenderer is useful for drawing directly into cells (i.e. text rendering and custom cell painting), it is a cumbersome model to use if you want to draw a component as part of an editor/renderer pair. For example, if you wanted to use a dropdown list in a grid cell, creating a renderer based on JCLightCellRenderer forces you to write the code that draws the arrow button. Obviously, it is more desirable to use the actual code for the component itself, for which is exactly what JCComponentCellRenderer is best suited.

Component-based cell renderers use an existing lightweight component for rendering the contents of a cell. As such, the JCComponentCellRenderer interface can be used to create a component-based cell renderer:

public interface JCComponentCellRenderer extends JCCellRenderer {
public Component getRendererComponent(JCCellInfo cellInfo, Object o,
      boolean selected);

}

The getRendererComponent returns the component that is to be used to render the cell. It is the responsibility of the implementor to use the information provided by getRendererComponent to set up the component for rendering:

As an example, consider JCLabelCellRenderer.java from com.klg.jclass.cell.renderers, which uses a Swing JLabel for rendering String data.

import com.klg.jclass.cell.JCComponentCellRenderer;
import com.klg.jclass.cell.JCCellInfo;
import javax.swing.JLabel;
import javax.swing.JComponent;

public class JCLabelCellRenderer extends JLabel
implements JCComponentCellRenderer {

public JCLabelCellRenderer() {
  super();
}

public JComponent getRendererComponent(JCCellInfo cellInfo,
                     Object o,boolean selected) {

  if (o != null) {
    if (o instanceof String) {
      setText((String)o);
    }
    else {
      setText(o.toString());
    }
  }
  else {
    setText("");
  }
  setBackground(cellInfo.getBackground());
  setForeground(cellInfo.getForeground());
  return this;
  }
  }

In this example, note that JCLabelCellRenderer extends JLabel, which makes it easier for the renderer to control the label's appearance.

In getRendererComponent(), object o is converted to a String and used to set the Text property of the label. Then, the font, foreground color, and background color are extracted from the cellInfo. Finally, the JLabel instance is passed back to the container.

JCComponentCellRenderer is a very powerful rendering model. While it is not as flexible as JCLightCellRenderer, it allows the reuse of code by using a lightweight component as a rubberstamp for painting in a cell. Any existing lightweight container can be used to render data inside of a cell - even other JClass components.


4.4 Editing Cells

While rendering cells is fairly straightforward, handling interactive cell editing is considerably more complex. Cell editing involves coordinating the user-interactions that begin and end the edit with cell data validation and connections to the data source. In JClass, cell editing is handled using the JCCellEditor interface.

A typical cell edit works through the following process:

Because cell editing has been designed to be flexible, you can have as little or as much control over the editing process as you want. The following sections explain cell editing in further detail.

4.4.1 Default Cell Editors

The following editors are provided in the com.klg.jclass.cell.editors package:

Editor

Description

BaseCellEditor

Provides a base editing component for other editors.

JCBigDecimalCellEditor

An editor using a simple text field for BigDecimal objects.

JCBooleanCellEditor

Provides a simple text editing component that allows the user to set the Boolean value as either 'true', 'false', 't' or 'f'.

JCByteCellEditor

An editor using a simple text field for Byte objects.

JCCheckBoxCellEditor

An editor for Boolean data that automatically changes the checked state.

JCComboBoxEditor

An editor using a simple Swing JComboBox for editing an enum.

JCDateCellEditor

An editor using a simple text field for Date objects

JCDoubleCellEditor

An editor using a simple text field for Double objects.

JCFloatCellEditor

An editor using a simple text field for Float objects.

JCImageCellEditor

An editor using a simple text field for Image objects.

JCIntegerCellEditor

An editor using a simple text field for Integer objects.

JCLongCellEditor

An editor using a simple text field for Long objects.

JCMultilineCellEditor

A simple text editing component for multiline data.

JCShortCellEditor

An editor using a simple text field for Short objects.

JCSqlDateCellEditor

An editor using a simple text field for SQL Date objects.

JCSqlTimeCellEditor

An editor using a simple text field for SQL Time objects.

JCSqlTimestampCellEditor

An editor using a simple text field for SQL Timestamp objects.

JCStringCellEdtitor

Provides a simple text editing component.

JCWordWrapCellEditor

Provides a simple text editing component that wraps text.

While these classes provide editing capability for most data types, many real-world situations require greater control over cell editing, editing components, and their relationships to specific data types. The following sections explore how you can more minutely control the cell editing mechanism in your programs.

4.4.2 Mapping a Data Type to a Cell Editor

It is likely that your grid is designed in such a way that there are many different data types within a row. In this case HiGrid creates a mapping between data types and cell editors. The mapping takes a data type and associates it with a cell editor; whenever the container encounters that type of data, it uses the mapped JCCellEditor.

Mapping a JCCellEditor object to a data type takes the following construction, where cellType is the cell editor and thisCell is the current cell:

thisCell.CellFormat.setCellEditorName(String cellType);

Normally, you would use these mappings in a construction that would test for the presence of the editor you specify, and throw an exception if the class was not found.

4.4.3 Creating Your Own Cell Editors

To create a cell editor object, you must implement the com.klg.cell.JCCellEditor interface. The following code comprises the JCCellEditor interface:

  public interface JCCellEditor extends JCCellEditorEventSource, serializable{
  public void initialize(AWTEvent ev, JCCellInfo info, Object o);
  public Component getComponent();
  public Object getCellEditorValue();
  public boolean stopCellEditing();
  public boolean isModified();
  public void cancelCellEditing();
  public JCKeyModifier[] getReservedKeys();
  }

Consider each of the methods in JCCellEditor:

Method and Description

public void initialize(AWTEvent ev, JCCellInfo info, Object o);

 

The table calls initialize() before the edit starts to let the editor know what kind of event started the edit, using java.awt.AWTEventObject. The size of the cell comes from the JCCellInfo interface (detailed below). The initialize() method also provides the data object (Object o).

public Component getComponent();

 

Returns the AWT component that does the editing. The component should be lightweight.

public Object getCellEditorValue();

 

Returns the value contained in the editor. This method is called by the table when the edit is complete. The value will be sent to the data source.

public boolean stopCellEditing();

 

When this method is called by the table, the editor can refuse to commit invalid values by returning false. This tells the container that the edit is not valid.

public boolean isModified();

 

The container uses this method to check whether the data has changed. This can save unnecessary access to the data source when the data has not actually changed.

public void cancelCellEditing();

 

Called by the table to stop editing and restore the cell's original contents.

public JCKeyModifier[] getReservedKeys();

 

Retrieves the keys the editor would like to reserve for itself. In order to avoid the container overriding key processing in the editor, the editor can pass back a list of keys it wishes to reserve. The container can refuse the editor's request to reserve keys. Most editors can simply return null for this method.

Because the JCCellEditor interface extends JCCellEditorEventSource, the following two methods are required to manage JCCellEditor event listeners:

Method and Description

public abstract void addCellEditorListener(JCCellEditorListener l);

 

Adds a listener to the list that's notified when the editor starts, stops, or cancels editing.

public abstract void removeCellEditorListener(JCCellEditorListener l);

 

Removes the listener.

In addition to implementing the methods of JCCellEditor, an editor is responsible for monitoring events and sending editingStopped and editingCanceled events to the grid. This functionality is further explained in Section 4.4.3, Creating Your Own Cell Editors.

Subclassing the Default Editors

One easy way to create your own editor is to subclass one of the editors provided in the com.klg.jclass.cell.editors package. The following code creates a simple editor that extends the JCStringCellEditor class. The MoneyCellEditor class formats the data as money (two digits to the right of the decimal point) instead of a raw String; but JCStringCellEditor does most of the work.

The initialize() method in MoneyCellEditor takes the object passed in and creates a Money value for it. The getCellEditorValue() method will pass the Money value back to the container.

import java.awt.Dimension;
import com.klg.jclass.cell.editors.JCStringCellEditor;
import com.klg.jclass.cell.JCCellInfo;
import java.awt.AWTEvent;

public class MoneyCellEditor extends JCStringCellEditor {

Money initial = null;

public void initialize(AWTEvent ev, JCCellInfo info, Object o) {
  if (o instanceof Money) {
    Money data = (Money)o;
    initial = new Money(data.dollars, data.cents);
  }
  super.initialize(ev, info, initial.dollars+"."+initial.cents);

}

public Object getCellEditorValue() {
  int d, c;
  String text = getText().trim();
  Money new_data = new Money(initial.dollars, initial.cents);

  try {
    // one of these will probably throw an exception if
    // the number format is wrong
    d = Integer.parseInt(text.substring(0,text.indexOf('.')));
    c = Integer.parseInt(text.substring(text.indexOf('.')+1));

    new_data.setDollars(d);
    // this will throw an exception if there's an invalid
    // number of cents
    new_data.setCents(c);
  }
  catch(Exception e) {
    return null;
  }

  return new_data;
}

public boolean isModified() {
  if (initial == null) return false;
  Money nv = (Money)getCellEditorValue();
  if (nv == null) return false;
  return (initial.dollars != nv.dollars || initial.cents != nv.cents);
}
}

Starting with one of the cell editors provided with the com.klg.cell.editors package can save you a lot of work coding entire editors on your own.

Writing Your Own Editors

Of course, you may not want to subclass any of the editors provided with the com.klg.jclass.cell.editors package. The following code fragment is from an editor that was written without subclassing an existing editor. By implementing the JCCellEditor interface, we have written an editor that will edit triangles. The editor handles both Integer and Polygon data types. It initializes the editor with the object to be edited, either a Number or a Polygon:

  ....

  public void initialize(AWTEvent ev, CellInfo info, Object o) {
   if (o instanceof Polygon) {
   orig_poly = (Polygon)o;
   }
   else if (o instanceof Number) {
   // Create polygon from the number
   int s = ((Number)o).intValue();
   orig_poly = new Polygon();
   orig_poly.addPoint(0,0);
   orig_poly.addPoint(0,s);
   orig_poly.addPoint(s,0);
   }
  
   new_poly = null;
  
   margin = info.getMarginSize();
  }
  

The editor also needs to retrieve the AWT component that will be associated with it. In this case the editor is an a javax.swing.JComponent object.

  ....
  public Component getComponent() {
   return this;
  }

The isModified() method checks to see if the editor has changed the data, and getCellEditorValue() which returns the new Polygon created.

  ....
  public boolean isModified() {
   return new_poly != null;
  }
  
  public Object getCellEditorValue() {
   return new_poly;
  }
  

The JCCellEditor interface defines the stopCellEditing() method, which stops and commits the editing operation. In the case of this example, there isn't any validation taking place, so the stopCellEditing() method will be unconditionally obeyed. The TriangleCellEditor also defines a cancelCellEditing() method, which resets the new Polygon.

  ....
  public boolean stopCellEditing() {
   return true;
  }
  
  public void cancelCellEditing() {
   new_poly = null;
   return;
  }

The editor contains a local method for retrieving a non-null polygon for drawing:

  ....
  private Polygon getDrawPoly() {
   if (new_poly == null)
   return orig_poly;
   return new_poly;
  }

The editor also has to determine the minimum size for the cell.

  ....
  public Dimension minimumSize() {
   Rectangle r = getDrawPoly().getBoundingBox();
   return new Dimension(r.width+r.x,r.height+r.y);
  }

Finally, the editor needs to know how to paint the current polygon into the cell:

  ....
public void paintComponent(Graphics gc) {
  // No L&F, so paint your own background.
  if (isOpaque()) {
    if (!gc.getColor().equals(getBackground())) {
      gc.setColor(getBackground());
    }
    Rectangle r = getBounds();
    gc.fillRect(0, 0, r.width, r.height);
  }

  int x, y;

  Polygon local_poly = getDrawPoly();
  gc.setColor(cellInfo.getForeground());
  gc.translate(margin.left, margin.top);
  gc.fillPolygon(local_poly);
  
  for(int i = 0; i < local_poly.npoints; i++) {
    x = local_poly.xpoints[i];
    y = local_poly.ypoints[i];
    gc.drawOval(x-2,y-2,4,4);
  }
  
  gc.translate(-margin.left, -margin.top);
}

Much of the rest of the editor handles mouse events to drag the triangle points, or to move the whole triangle inside the cell. See the example file for this code.

Finally, the editor contains event listener methods that add and remove listeners from the listener list. These listeners are notified when the editor starts, stops, or cancels an edit.

  JCCellEditorSupport support = new JCCellEditorSupport();
  ....
  public void addCellEditorListener(CellEditorListener l) {
   support.addCellEditorListener(l);
  }
  
  public void removeCellEditorListener(CellEditorListener l) {
   support.removeCellEditorListener(l);
  }

Note that an instance of com.klg.jclass.cell.JCCellEditorSupport is used to manage the listener list. The JCCellEditorSupport class is a useful convenience class for editors that want to send events to JClass HiGrid programs.

The TriangleCellEditor is an example of a fairly complex implementation of the JCCellEditor interface. It contains all of the core methods of the interface, and extends the capabilities for an interesting type of data. You can use this example to help you to write your own JCCellEditor classes that handle any type of data you care to display and edit.

Handling Editor Events

The com.klg.jclass.cell package contains several event and listener classes that enable cell editors and their containers to inform each other of changes to the cell contents, and allow you to control validation of the cell's edited contents.

The simplest way to handle JCCellEditor events is to use the JCCellEditorSupport convenience class. JCCellEditorSupport makes it easy for cell editors to implement standard editor event handling by registering event listeners and providing easy methods for sending events.

JCCellEditorSupport methods include:

Method

Description

addCellEditorListener()

Adds a new JCCellEditorListener to the listener list.

removeCellEditorListener()

Removes a JCCellEditorListener from the list.

fireStopEditing()

Sends an editingStopped event to all listeners.

fireCancelEditing()

Sends an editingCanceled event to all listeners.

For example, consider the TriangleCellEditor. The changes made are not actually sent to the data source until the user clicks on another cell. It is more useful to have the editor send an editingStopped event when the mouse button is released:

  public void mouseReleased(MouseEvent e) {
   support.fireStopEditing(new JCCellEditorEvent(e));
  }

For more complete control, however, you will have to use the other event handling classes provided in the com.klg.jclass.cell package:

Method

Description

JCCellEditorEvent

Sent when the JCCellEditor finishes an operation. The JCCellEditorEvent contains the event that originated the operation in the editor.

JCCellEditorListener

The container registers a JCCellEditorListener to let the JCCellEditor inform it when editing has stopped or been canceled.

JCCellEditorEventSource

This class defines the add and remove methods for an object that posts JCCellEditorEvents.

Editor Key Control

Sometimes, you may want your cell editor to be able to accept keystrokes that have already been reserved for a specific purpose in the container (a Tab key in HiGrid, for example). To do this, you need to use the JCKeyModifier class to reserve a key/modifier combination:

  JCKeyModifier(int key, int modifier, boolean canInitializeEdit);

Using this class, you can reserve a key for a particular modifier or for all modifiers. To reserve Ctrl-Tab and Shift-Tab you would specify two JCKeyModifier objects with standard KeyEvent modifiers; for example, KeyEvent.ALT_MASK.

If you want to reserve all Tab keys for the editor, you can use either of the following:

Note that the container can still choose to ignore reserved keys.


4.5 The JCCellInfo Interface

You can see that JCComponentCellRenderer, JCLightCellRenderer and JCCellEditor use the JCCellInfo interface to get information about the cell. The JCCellInfo interface provides information about how the container wants to show the cell. The renderer and editor determine whether or not to honor the container's request.

The JCCellInfo interface gives the renderer and editor access to cell formatting information from the cells of the grid, including:

This information is fairly generic. The com.klg.jclass.higrid package also contains an object called CellFormat, which extends CellStyle and implements JCCellInfo to include more detailed information from the grid.

Figure 42 :  The relationship of border sides, margins, and drawing
area provided by JCCellInfo.

The following code comprises the com.klg.jclass.cell.JCCellInfo interface:

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Font;
import java.awt.Insets;
import javax.swing.SwingConstants;

public interface JCCellInfo {
public Color getBackground();
public Color getForeground();
public Color getSelectedBackground();
public Color getSelectedForeground();
public Font getFont();
public int getHorizontalAlignment();
public int getVerticalAlignment();
public Insets getMarginInsets();
public Insets getBorderInsets();
public int getBorderStyle();
public Rectangle getDrawingArea();
public boolean isEditable();
public boolean isEnabled();
public boolean getSelectAll();
public int getClipHints();
public Class getDataType();

PreviousNextIndex