Epiphyte.net dev Christina Schulman

/**
 * 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")); } } }