Friday, August 25, 2006

Custom Cell Renderers and Custom Cell Editors in Swing - Part III

Now lets take a look at how the CustomJTable code looks like. In order to allow external controllers to specify which column of the JTable will render itself as JRadioButtons, we have a method called setRadioGroup.  We also declare the custom Table Model which hides our internal structure and works the Model magic of Swing by extending AbstractTableModel.

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

public class CustomJTable extends JTable {

  /**
   * Give support for Grouping Radio Buttons in
   * different rows of a specific column in the table
   <br>
   * Optionally also allow a CellRendererValidator
   * which can choose which rows in the table will
   * have the radio button visible
   
   @param columnIndex -
   *            The column to which the grouping must
   *            be enabled
   
   @param validator -
   *            An optional CellRendererValidator to
   *            choose which columns have visible
   *            radio buttons. By default all column
   *            will show the radiobutton
   
   @see CellRendererValidator
   */
  public void setRadioGroup(int columnIndex,
      CellRendererValidator validator) {
    getColumnModel().getColumn(columnIndex)
        .setCellEditor(
            new RadioColumnCellEditor());
    getColumnModel().getColumn(columnIndex)
        .setCellRenderer(
            new RadioColumnRenderer(
                validator));
  }

  public boolean isCellEditable(int rowIndex,
      int vColIndex) {
    return true;
  }

  public Class getColumnClass(int column) {
    Object value = getValueAt(0, column);
    if (value != null)
      return value.getClass();
    else
      return super.getColumnClass(column);
  }

  /**
   * CellRendererValidator - This is an interface
   * that will be implemented by any class that
   * wishes <br>
   * to specify whether a CellRenderer is valid for a
   * specific column and row. <br>
   * This is pretty useful when specific rows of a
   * column will <i>NOT </i> the renderer set for the
   * entire column
   
   @author rajeshv
   */
  public static interface CellRendererValidator {
    public boolean isValid(JTable table,
        int rowIndex, int colIndex);
  }

  public static class CustomJTableModel extends
      AbstractTableModel {
    private List dataList = null;

    private String[] properties = null;

    public CustomJTableModel(List list) {
      dataList = list;
      LinkedHashMap map =
          (LinkedHashMapdataList.get(0);
      Set keySet = map.keySet();
      properties = new String[keySet.size()];
      int index = 0;
      for (Iterator iter = keySet.iterator(); iter
          .hasNext();) {
        properties[index++=
            (Stringiter.next();
      }
    }

    public int getColumnCount() {
      LinkedHashMap table =
          (LinkedHashMapdataList.get(0);
      return table.size();
    }

    public Object getValueAt(int rowIndex,
        int columnIndex) {
      LinkedHashMap table =
          (LinkedHashMapdataList
              .get(rowIndex);
      return table.get(properties[columnIndex]);
    }

    public int getRowCount() {
      return dataList.size();
    }

    public String getColumnName(int columnIndex) {
      return properties[columnIndex];
    }

    public Class getColumnClass(int columnIndex) {
      return String.class;
    }

    public void setValueAt(Object aValue,
        int rowIndex, int columnIndex) {
      LinkedHashMap table =
          (LinkedHashMapdataList
              .get(rowIndex);
      table.put(properties[columnIndex], aValue);
      fireTableCellUpdated(rowIndex, columnIndex);
    }

    public boolean isCellEditable(int rowIndex,
        int columnIndex) {
      return false;
    }
  }

  public static void main(String[] args) {
    CustomJTable table = new CustomJTable();
    LinkedHashMap firstRow = new LinkedHashMap();
    firstRow.put("column1""test1");
    firstRow.put("column2", Boolean.TRUE);
    LinkedHashMap secondRow = new LinkedHashMap();
    secondRow.put("column1""test1");
    secondRow.put("column2", Boolean.FALSE);
    LinkedHashMap thirdRow = new LinkedHashMap();
    thirdRow.put("column1""test1");
    thirdRow.put("column2""test");

    List dataList = new ArrayList();
    dataList.add(firstRow);
    dataList.add(secondRow);
    dataList.add(thirdRow);
    table
        .setModel(new CustomJTable.CustomJTableModel(
            dataList));
    table
        .setRadioGroup(
            1,
            new CustomJTable.CellRendererValidator(){
              public boolean isValid(
                  JTable table,
                  int rowIndex,
                  int colIndex) {
                if (rowIndex == 2) {
                  return false;
                }
                return true;
            });
    JFrame frame = new JFrame();
    frame
        .setDefaultCloseOperation(
                        
JFrame.EXIT_ON_CLOSE);
    frame.setSize(600600);
    frame.getContentPane().add(table);
    frame.setVisible(true);
  }
}

No comments: