/**
* EventCellTable.java
*
* Copyright 2003 by Christina Schulman
*
* This code has been tested under JDK 1.3.1, but might act
* strangely under other versions of the JDK.
*
* Disclaimer: This code is provided "as is"; all warranties
* express and implied are disclaimed; I am not liable for
* anything you do with this, ever; do not take internally;
* do not taunt Happy Fun Ball.
*
* For more code samples, see http://www.epiphyte.net/dev/.
*/
package net.epiphyte.sample.gui.EventCellTable;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.util.EventObject;
import java.util.Hashtable;
/**
* EventCellTable is a simple stand-alone example of a JTable
* that can display AWT/Swing Components in its cells, and
* allows those components (and their contents) to receive
* events.
*
* This example uses ActionEvents. Other events can also
* be used, although MouseEvent enter and exit events are
* not always reliably generated.
*
* @author Christina Schulman
* @author http://www.epiphyte.net
* @version 1.0
* @see javax.swing.JTable
* @see javax.swing.table.TableCellEditor
* @see javax.swing.table.TableCellRenderer
* @since 12 May 2003
*/
public class EventCellTable extends JTable
{
/**
* Creates an EventCellTable within a JFrame.
*
* @param args Command-line args (ignored).
*/
public static void main(String args[])
{
// Create a frame to display the demo
JFrame frame = new JFrame("EventCellTable demo");
frame.setSize(600, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(false);
// Center the frame on the screen
Dimension sd = Toolkit.getDefaultToolkit().getScreenSize();
Dimension fd = frame.getSize();
frame.setLocation((sd.width/2)-(fd.width/2), (sd.height/2)-(fd.height/2));
// Create & add the EventCellTable
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add((new JScrollPane(new EventCellTable())),
BorderLayout.CENTER);
frame.setVisible(true);
}
/**
* Create an EventCellTable. Dummy data and components are
* hardcoded, because it's just a little demo.
*/
public EventCellTable()
{
final int NUM_ROWS = 9;
final String[] columnNames = {"single button", "button panel", "just some text"};
int numCols = columnNames.length;
Object[][] values = new Object[0][numCols];
// Initialize the table model with the column headers
setModel(new DefaultTableModel(values, columnNames));
// Cosmetic settings. Mess with these if you want to change
// how other cells in the row are highlighted when the user
// clicks on a button in a component cell.
setRowSelectionAllowed(true);
setColumnSelectionAllowed(false);
// Create single instances of the cell renderer and cell
// editor. These will be used for component-based columns,
// but not for the text column, which just uses the
// default cell renderer and editor.
ComponentRenderer cellrenderer = new ComponentRenderer();
ComponentEditor celleditor = new ComponentEditor();
// Set component-aware renderer and editor for single-button column
getColumnModel().getColumn(0).setCellRenderer(cellrenderer);
getColumnModel().getColumn(0).setCellEditor(celleditor);
// Set component-aware renderer and editor for button-panel column
getColumnModel().getColumn(1).setCellRenderer(cellrenderer);
getColumnModel().getColumn(1).setCellEditor(celleditor);
// Add data to the table, including components
for (int row = 0; row < NUM_ROWS; row++) {
// Add the new row
String[] rowData = new String[getModel().getColumnCount()];
rowData[2] = "value for row #" + row;
((DefaultTableModel) getModel()).addRow(rowData);
// Add the new components
setValueAt((new CellButton("button " + row)),row,0);
setValueAt((new CellPanel("panel " + row)),row,1);
}
}
/**
* Inner class ComponentRenderer
*
* Renderer that allows AWT/Swing components to display correctly.
*/
class ComponentRenderer implements TableCellRenderer
{
/**
* Returns the component used for drawing the cell. This method is
* used to configure the renderer appropriately before drawing.
*
* @param table The invoking JTable; can be null.
* @param value The value of the cell to be rendered. Here, the component.
* @param isSelected True if the cell should to be highlighted.
* @param hasFocus True if the cell currently has the editing focus.
* @param row The row index of the cell being drawn.
* @param column The column index of the cell being drawn.
*
* @return The value itself, cast to a Component, since it can render itself.
*/
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
if (value instanceof Component) {
return (Component) value;
}
else {
return null;
}
}
}
/**
* Cell editor that lets AWT/Swing components receive events.
*/
class ComponentEditor extends AbstractCellEditor implements TableCellEditor
{
/**
* Stores the component currently being edited.
*/
Component comp_ = null;
/**
* Returns the value contained in the editor.
*
* @return The component value currently being edited.
*/
public Object getCellEditorValue()
{
return comp_;
}
/**
* Sets an initial value for the editor. This will cause
* the editor to stopEditing and lose any partially
* edited value if the editor is editing when this method is called.
*
* Returns the component that should be added to the client's
* Component hierarchy. Once installed in the client's
* hierarchy this component will then be able to draw and receive
* user input.
*
* @param table The invoking JTable; can be null.
* @param value The value of the cell to be edited. Here, the component.
* @param isSelected True if the cell should to be highlighted.
* @param row The row of the cell being edited.
* @param column The column of the cell being edited.
*
* @return The component itself, so that it can receive user events.
*/
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column)
{
if (value instanceof Component) {
comp_ = (Component) value;
return (Component) value;
}
else {
return null;
}
}
}
/**
* Example button class that handles its own Action Events.
*
* When the button is pressed, a message box pops up with the button's title.
*/
class CellButton extends JButton implements ActionListener
{
/**
* Creates a button with the supplied title, and adds itself
* as its own ActionListener.
*
* @param szText Button title.
*/
public CellButton(String szText)
{
super(szText);
addActionListener(this);
}
/**
* Invoked when this button is pressed; just displays a thrilling
* message box to tell the user which button was pressed.
*
* @param e ActionEvent that fired this method.
*/
public void actionPerformed(ActionEvent e) {
if ((e != null) && (e.getSource() == this)) {
JOptionPane.showMessageDialog(null, getText() + " was pressed!");
}
}
}
/**
* Example panel that contains a couple of buttons.
*/
class CellPanel extends JPanel
{
/**
* Creates a panel that contains two CellButtons, laid out horizontally.
*
* @param szText Panel title, used to give its buttons
* unique (hopefully) names.
*/
public CellPanel(String szText)
{
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(new CellButton(szText + "-A"));
add(new CellButton(szText + "-B"));
}
}
}