4
Displaying and Editing Cells
Overview Default Cell Rendering and Editing
Rendering Cells Editing Cells The JCCellInfo Interface
4.1 Overview
JClass LiveTable offers a flexible way to display and edit any type of data contained in a table's cells. The following sections explain the techniques for displaying and editing cells in your programs.
In order to display a cell, JClass LiveTable 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, LiveTable 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
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 onJComponent
JCLightCellRenderer
: allows the creation of renderers based on direct drawingContains editors for common data types.
Please see Section 4.4.1, Default Cell Editors, for details.
Contains renderers for common data types, including expressions.
Please see Section 4.3.1, JClass Cell Renderers, for details.
This JClass cell package is generic; renderers and editors written for JClass LiveTable will work with other JClass products. In addition, JClass Field components can work as renderers and editors within JClass LiveTable, allowing very lightweight operation.
Note: For the JClass Field component to work as a renderer, you need to use a particular instance from the
com.klg.
jclass.field.cell
package.JClass LiveTable 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. For example, if JClass LiveTable encounters an expression in a cell (for example, any formula from com.klg.jclass.util.formulae), the default
JCExpressionCellRenderer
will be used.Often, however, you will want to control the way data in a particular area of the table 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 table draws itself, it accesses the data source and attempts to paint the contents of each cell. In doing so, it works through a two-stage process:
The following table lists the cell renderers and editors for common data types included with JClass LiveTable, which are found in the
com.klg.
jclass.cell.renderers
andcom.klg.
jclass.cell.editors
packages, respectively. When going through the above steps, JClass LiveTable uses these default mappings.Although these editors and renderers are included with JClass LiveTable, 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 LiveTable includes renderers that you can use in your table. Additionally, two rendering models,
JCLightCellRenderer
andJCComponentCellRenderer
, are provided if you want to create your own renderer. Each model caters to different rendering needs.More information about included renderers is 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.4, Creating your own Cell Renderers.
4.3.1 JClass Cell Renderers
As shown in the table above, JClass LiveTable maps standard data types to specific renderers when the program does not specify a renderer for that data type (either by setting for a series or mapping). This means that most tables are easily rendered without any special coding. The renderers are internally assigned. JClass LiveTable also contains several cell renderers for specific data types that you can set for a series (see Section 4.3.2, Setting a Cell Renderer for a Series) or as a mapping (see Section 4.3.3, Mapping a Data Type to a Cell Renderer). These cell renderers are described in the following table and all of them are in
com.klg.
jclass.cell.renderers
package.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 LiveTable includes ways for you to customize cell rendering as described in Section 4.3.4, Creating your own Cell Renderers.
4.3.2 Setting a Cell Renderer for a Series
Often, the rows and columns that comprise a table are grouped by the type of data they contain. You may be creating an order form that has a product name (a String) in one column, a part number (an Integer) in another, and a check box (a special type of object) in the final column to indicate that you want that product. For example:
All of these columns take a different data type, so their data is all rendered differently. LiveTable will automatically detect the type of data found, and use one of the default renderers for that column (please see Section 4.2, Default Cell Rendering and Editing, for a list of default renderers). However, you can use your own renderer if the default does not suit your needs.
In the case of the Order check box, the default renderer for its Boolean data type will be the
JCStringCellRenderer
. With this default renderer, since the data type is boolean, instead of having a check (or no check) painted onto the cell, "true" or "false" will appear. This is not desirable, so you need to deviate from JClass LiveTable's default renderer.To set a new cell renderer for a range of cells, use a cell style, which has its own cell renderer property (for more information, please refer to Cell Styles, in Chapter 2). Inserting these lines of code into your program will do this:
CellStyleModel style = table.getUniqueCellStyle(0,3);
style.setCellRenderer(new JCCheckBoxCellRenderer());
table.setCellStyle(JCTableEnum.ALL, 3, style);The
JCCheckBoxCellRenderer
class defines an object that paints boolean objects in a table cell as checks. This way, the first two columns render automatically with the defaults, and the third column will use your defined renderer.
4.3.3 Mapping a Data Type to a Cell Renderer
Even though you can set the renderer series, your table may be designed in such a way that the data types within a row or column are not consistent, or will change depending on the data source. In this case you could decide not to set the renderer series at all, and allow the container to evaluate the data type and provide the appropriate renderer. Unfortunately, this means you have to use the default renderers for a given data type.
To use your own renderers without sacrificing flexibility, you can create a mapping. The mapping takes a data type and associates it with a
JCCellRenderer
object; whenever the container encounters that type of data, it uses the mappedJCCellRenderer
object to render the data object in the cell.Mapping a
table.setCellRenderer(Class cellType, Class renderer);JCCellRenderer
object to a data type takes the following construction:For example, in the following code fragment (from TriangleTable.java in the examples/table/cell directory of the JClass distribution), the cell renderer is set for a particular data type, defined by
try {java.awt.Polygon
.
table.setCellRenderer(Class.forName("java.awt.Polygon"),
Class.forName
("examples.table.cell.TriangleCellRenderer"));
....
}
catch (ClassNotFoundException e) {
e.printStackTrace(System.out);
}
}The
table.setCellRenderer()
method takes a class to define the data type and a class to define the renderer. In the case below, we have created a class calledTriangleCellRenderer
, which is identified using theClass.forName()
method imported fromjava.lang.Class
. (Creating your own cell renderers is explained in the next section.)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 renderer class was not found, as is the case in the above sample.
To "unmap" a renderer, set the renderer class parameter to null.
Alternatively, you can map a particular cell renderer instance to a data type using:
table.setCellRenderer(Class cellType, JCCellRenderer renderer);This method is useful if you want to reuse the same renderer instance, or if your renderer does not have a default construction.
4.3.4 Creating your own Cell Renderers
Naturally, the renderer classes provided with JClass LiveTable 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.
The examples/table/cell directory and the demos/table directories of your JClass LiveTable distribution contain a wide array of sample programs that use different approaches to cell rendering. You can use these examples and demos to help you refine your own renderers for whatever purpose you require.
Subclassing the Default Renderers
A simple way to create your own renderer objects is to subclass one of the renderers provided with JClass LiveTable. For example, CurrencyRenderer.java, found in the examples/table/cell directory, is an example of subclassing from the
import com.klg.jclass.cell.renderers.JCStringCellRenderer;JCStringCellRenderer
in thecom.klg.
jclass.cell.renderers
package:
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 LiveTable 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
public interface JCLightCellRenderer {com.klg.
jclass.cell.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:
- A
draw()
method, which is passed aJCCellInfo
object (see Section 4.5, The JCCellInfo Interface, for more details) containing information from the container about the cell, ajava.awt.Graphics
object, and the object to be rendered. TheGraphics
object is positioned at the origin of the cell (0,0), but is not clipped.- A
getPreferredSize()
method, which is used to allow the renderer to influence the container's layout. The container may not honor the renderer's request, depending on a number of factors.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
public void draw(Graphics gc, JCCellInfocellInfo,JCCellRenderer
, the program contains adraw()
method in the lines:
Object o boolean selected) {
Polygon p = makePolygon(o);
gc.getColor(selected ? cellInfo.getSelectedForeground():
cellInfo.getForeground());
gc.fillPolygon(p);
}The
draw()
method renders the objecto
by making it into a polygon and drawing the polygon using thegc
provided. Table, as the container, automatically translates and clips thegc
, 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 theJCCellInfo
interface (see Section 4.5, The JCCellInfo Interface).The second required method,
public Dimension getPreferredSize(Grahpics gc, JCCellInfo cellInfo,getPreferredSize()
, is provided in the lines:
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 Table container.Creating a Component-based Cell Renderer with JCComponentCellRenderer
While
JCLightCellRenderer
is useful for drawing directly into cells (that is, 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 drop-down list in a table cell, creating a renderer based onJCLightCellRenderer
forces you to write the code that draws the arrow button. Obviously, it is more desirable to use the actual code for the component - this is exactly for whatJCComponentCellRenderer
is best suited.Component-based cell renderers use an existing lightweight component for rendering the contents of a cell. As such, the
public interface JCComponentCellRenderer extends JCCellRenderer {JCComponentCellRenderer
interface can be used to create a component-based cell renderer:
public Component getRendererComponent(JCCellInfo cellInfo, Object o,
boolean selected);
}The
getRendererComponent()
method returns the component that is to be used to render the cell. It is the responsibility of the implementor to use the information provided bygetRendererComponent()
to set up the component for rendering:
cellInfo
contains information from the container about the cell (see Section 4.5, The JCCellInfo Interface, for more details).o
is the object to be rendered.selected
is a boolean indicating whether the cell is selected. Many implementors use this information to modify the component appearance.As an example, consider JCLabelCellRenderer.java from
import com.klg.jclass.cell.JCComponentCellRenderer;com.klg.
jclass.cell.renderers
, which uses a SwingJLabel
for rendering String data.
import com.klg.jclass.cell.JCCellInfo;
import javax.swing.JLabel;
import java.awt.Component;
public class JCLabelCellRenderer extends JLabel
implements JCComponentCellRenderer {
public JCLabelCellRenderer() {
super();
}
public Component getRendererComponent(JCCellInfo cellInfo, Object o,
boolean selected) {
if (o != null) {
if (o instanceof String) {
setText((String)o);
}
else {
setText(o.toString());
}
}
else {
setText("");
}
setFont(cellInfo.getFont());
setBackground(selected ? cellInfo.getSelectedBackground() :
cellInfo.getBackground());
setForeground(selected ? cellInfo.getSelectedForeground() :
cellInfo.getForeground());
setHorizontalAlignment(cellInfo.getHorizontalAlignment());
setVerticalAlignment(cellInfo.getVerticalAlignment());
return this;
}
}In this example, note that
JCLabelCellRenderer
extendsJLabel
, which makes it easier for the renderer to control the label's appearance.In
getRendererComponent()
, the objecto
is converted to a String and used to set theText
property of the label. Then, the font, foreground color, and background color are extracted from thecellInfo
. Finally, theJLabel
instance is passed back to the container.
JCComponentCellRenderer
is a very powerful rendering model. While it is not as flexible asJCLightCellRenderer
, it allows the reuse of code by using a lightweight component as a rubber stamp 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:
- The container listens for events that come from the editor by implementing
JCCellEditorListener
.- When a user initiates a cell edit with either a mouse click or a key press, the container calls
JCCellEditor.initialize()
and passes aJCCellInfo
object with information about the cell, and the object (data) that will be edited.- The
JCCellEditor
displays the data and changes it according to user input.- If the user traverses out of the cell, then the container calls the
stopCellEditing()
method, which asks theJCCellEditor
to validate the edit. If the edit is not valid - that is,stopCellEditing()
returnsfalse
- the container then retrieves the original cell value from the data source. If the edit is valid, then the container callsgetCellEditorValue()
on the editor to retrieve the new value of the cell and send it to the data source.- If the user types a key that the editor interprets as "done" (for example, Enter), the editor will inform the table that the edit is complete by sending an
editingStopped
event to the table. Typical editors will validate the user's changes before sending the event.- If the user types a key that the editor interprets as "cancel" (for example, Esc), the editor will instruct the table to cancel the edit by sending an
editingCanceled
event.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
Cell editors are typically Swing components with extended functionality provided by the
com.klg.
jclass.table.cell.JCCellEditor
interface. Although every data object is guaranteed to have a cell renderer, not every object is guaranteed to have an editor. Unless an object has an editor, the cell is not editable, regardless of whether thetable.setEditable()
method has atrue
value for that cell. Most of the standard data types have default editors which are internally associated with that data type. If the program does not specify an editor for a series or map a data type to an editor, theTable
uses the default. The following editors are provided in thecom.klg.
jclass.cell.editors
package: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 Setting a Cell Editor for a Series
As mentioned above, JClass LiveTable contains logic that will map data types to their default editors. If you want to override these defaults, you can set a specific editor for a series of cells in your table by setting the
CellStyleModel style = table.getUniqueCellStyle(0,3);CellEditor
property on a cell style, for a range of cells:
style.setCellEditor(new JCStringCellEditor());
table.setCellStyle(JCTableEnum.ALL, 3, style);This code uses the same
CellEditor
(the default String editor in thecom.klg.
jclass.cell.editors
package) for all of the cells in the fourth column in the table.
4.4.3 Mapping a Data Type to a Cell Editor
Even though you can set the editor series, your table may be designed in such a way that the data types within a row or column are not consistent, or will change depending on the data source. In this case you can create a mapping. 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
table.setCellEditor(Class cellType, Class Editor);CellEditor
object to a data type takes the following construction:Consider the following sample from TriangleTable.java in the examples/table/cell directory of the JClass LiveTable distribution:
try {
table.setCellEditor(Class.forName("java.awt.Polygon"),
Class.forName
("examples.table.cell.TriangleCellEditor"));
}
catch (ClassNotFoundException e) {
e.printStackTrace(System.out);
}The
table.setCellEditor()
method takes a class to define the data type and a class to define the editor. In the case above, we have created a class calledTriangleCellEditor
, which is identified using theClass.forName()
method imported fromjava.lang.Class
. (Creating your own cell editors is explained in the next section).To "unmap" an editor, set the editor class parameter to
null
.Alternatively, you can map a cell editor to a data type using:
table.setCellEditor(Class cellType, JCCellEditor editor);This method is useful if you want to reuse the same editor instance, or if your editor does not have a default constructor.
Note: If the value for a particular cell is null, JClass LiveTable has no way of determining its type. This can cause problems if mapping a null value to an editor. To work around this, use the
DataType
property that is used with cell styles. LiveTable refers toDataType
when it encounters a null in the data source.
4.4.4 Creating Your Own Cell Editors
To create a cell editor object, you must implement the
public interface CellEditor extends JCCellEditorEventSource,com.klg.cell.JCCellEditor
interface. The following code comprises theJCCellEditor
interface:
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();
}This chart describes each of the methods in
JCCellEditor
:Because the
JCCellEditor
interface extendsJCCellEditorEventSource
, the following two methods are required to manageJCCellEditor
event listeners:In addition to implementing the methods of
JCCellEditor
, an editor is responsible for monitoring events and sendingeditingStopped
andeditingCanceled
events to the table. This functionality is further explained in 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 is from examples/table/cell/MoneyCellEditor.java. It creates a simple editor that extends theJCStringCellEditor
class. TheMoneyCellEditor
class formats the data as money (two digits to the right of the decimal point) instead of a raw String; butJCStringCellEditor
does most of the work.The
import java.awt.Dimension;initialize()
method inMoneyCellEditor
takes the object passed in and creates a Money value for it. ThegetCellEditorValue()
method will pass the Money value back to the container.
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 is from an editor that was written without subclassing an existing editor. By implementing theJCCellEditor
interface, we have written an editor that will edit triangles. The code is in examples/table/cell/TriangleCellEditor.java. You can see it work by runningexamples.table.cellTriangeTable
.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, andgetCellEditorValue()
which returns the new Polygon created.
public boolean isModified() {
return new_poly != null;
}
public Object getCellEditorValue() {
return new_poly;
}
The
....JCCellEditor
interface defines thestopCellEditing()
method, which stops and commits the editing operation. In the case of this example, there isn't any validation taking place, so thestopCellEditing()
method will be unconditionally obeyed. TheTriangleCellEditor
also defines acancelCellEditing()
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.JCCellEditorSupport
is a useful convenience class for editors that want to send events to JClass LiveTable programs.The
TriangleCellEditor
is an example of a fairly complex implementation of theJCCellEditor
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 ownJCCellEditor
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 theJCCellEditorSupport
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:For example, consider the
public void mouseReleased(MouseEvent e) {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 aneditingStopped
event when the mouse button is released:
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: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 LiveTable, for example). To do this, you need to use the
JCKeyModifier(int key, int modifier, boolean canInitializeEdit);JCKeyModifier
class to reserve a key/modifier combination: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 standardKeyEvent
modifiers, for exampleKeyEvent.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
andJCCellEditor
use theJCCellInfo
interface to get information about the cell. TheJCCellInfo
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 Table, including:
- foreground color
- background color
- selected foreground color
- selected background color
- font
- font metrics
- horizontal and vertical alignment
This information is fairly generic. The
com.klg.
jclass.table
package also contains an object calledTableCellInfoModel
, which extendsJCCellInfo
to include more detailed information from the Table.TableCellInfoModel
is useful for retrieving Table-specific information for use in the editor or renderer.Note that editors and renderers that rely on
TableCellInfoModel
can only be used with JClass LiveTable.
Figure 12 : The relationship of border sides, margins, and drawing
area provided by JCCellInfo.
For more information, please see the
JCCellInfo
API documentation.