/*
 * (swing1.1beta3)
 * 
 */package jp.gr.java_conf.tame.swing.table;import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
/**
 * @version 1.0 11/22/98
 */public class AttributiveCellTableModel extends DefaultTableModel {  protected CellAttribute cellAtt;
    
  public AttributiveCellTableModel() {
    this((Vector)null, 0);
  }
  public AttributiveCellTableModel(int numRows, int numColumns) {
    Vector names = new Vector(numColumns);
    names.setSize(numColumns);
    setColumnIdentifiers(names);
    dataVector = new Vector();
    setNumRows(numRows);
    cellAtt = new DefaultCellAttribute(numRows,numColumns);
  }
  public AttributiveCellTableModel(Vector columnNames, int numRows) {
    setColumnIdentifiers(columnNames);
    dataVector = new Vector();
    setNumRows(numRows);
    cellAtt = new DefaultCellAttribute(numRows,columnNames.size());
  }
  public AttributiveCellTableModel(Object[] columnNames, int numRows) {
    this(convertToVector(columnNames), numRows);
  }  
  public AttributiveCellTableModel(Vector data, Vector columnNames) {
    setDataVector(data, columnNames);
  }
  public AttributiveCellTableModel(Object[][] data, Object[] columnNames) {
    setDataVector(data, columnNames);
  }    
  public void setDataVector(Vector newData, Vector columnNames) {
    if (newData == null)
      throw new IllegalArgumentException("setDataVector() - Null parameter");
    dataVector = new Vector(0);
    setColumnIdentifiers(columnNames);
    dataVector = newData;
    
    //
    cellAtt = new DefaultCellAttribute(dataVector.size(),
                                       columnIdentifiers.size());
    
    newRowsAdded(new TableModelEvent(this, 0, getRowCount()-1,
 TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
  }  public void addColumn(Object columnName, Vector columnData) {
    if (columnName == null)
      throw new IllegalArgumentException("addColumn() - null parameter");
    columnIdentifiers.addElement(columnName);
    int index = 0;
    Enumeration enumeration = dataVector.elements();
    while (enumeration.hasMoreElements()) {
      Object value;
      if ((columnData != null) && (index < columnData.size()))
  value = columnData.elementAt(index);
      else
value = null;
      ((Vector)enumeration.nextElement()).addElement(value);
      index++;
    }    //
    cellAtt.addColumn();    fireTableStructureChanged();
  }  public void addRow(Vector rowData) {
    Vector newData = null;
    if (rowData == null) {
      newData = new Vector(getColumnCount());
    }
    else {
      rowData.setSize(getColumnCount());
    }
    dataVector.addElement(newData);    //
    cellAtt.addRow();    newRowsAdded(new TableModelEvent(this, getRowCount()-1, getRowCount()-1,
       TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
  }  public void insertRow(int row, Vector rowData) {
    if (rowData == null) {
      rowData = new Vector(getColumnCount());
    }
    else {
      rowData.setSize(getColumnCount());
    }    dataVector.insertElementAt(rowData, row);    //
    cellAtt.insertRow(row);    newRowsAdded(new TableModelEvent(this, row, row,
       TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
  }  public CellAttribute getCellAttribute() {
    return cellAtt;
  }  public void setCellAttribute(CellAttribute newCellAtt) {
    int numColumns = getColumnCount();
    int numRows    = getRowCount();
    if ((newCellAtt.getSize().width  != numColumns) ||
        (newCellAtt.getSize().height != numRows)) {
      newCellAtt.setSize(new Dimension(numRows, numColumns));
    }
    cellAtt = newCellAtt;
    fireTableDataChanged();
  }  /*
  public void changeCellAttribute(int row, int column, Object command) {
    cellAtt.changeAttribute(row, column, command);
  }  public void changeCellAttribute(int[] rows, int[] columns, Object command) {
    cellAtt.changeAttribute(rows, columns, command);
  }
  */
    
}

解决方案 »

  1.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;import java.awt.*;
    /**
     * @version 1.0 11/22/98
     */public class DefaultCellAttribute 
    //    implements CellAttribute ,CellSpan  {
          implements CellAttribute ,CellSpan ,ColoredCell ,CellFont {  //
      // !!!! CAUTION !!!!!
      // these values must be synchronized to Table data
      //
      protected int rowSize;
      protected int columnSize;
      protected int[][][] span;                   // CellSpan
      protected Color[][] foreground;             // ColoredCell
      protected Color[][] background;             //
      protected Font[][]  font;                   // CellFont
      
      public DefaultCellAttribute() {
        this(1,1);
      }
      
      public DefaultCellAttribute(int numRows, int numColumns) {
        setSize(new Dimension(numColumns, numRows));
      }  protected void initValue() {
        for(int i=0; i<span.length;i++) {
          for(int j=0; j<span[i].length; j++) {
    span[i][j][CellSpan.COLUMN] = 1;
    span[i][j][CellSpan.ROW]    = 1;
          }
        }
      }
      //
      // CellSpan
      //
      public int[] getSpan(int row, int column) {
        if (isOutOfBounds(row, column)) {
          int[] ret_code = {1,1};
          return ret_code;
        }
        return span[row][column];
      }  public void setSpan(int[] span, int row, int column) {
        if (isOutOfBounds(row, column)) return;
        this.span[row][column] = span;
      }
          
      public boolean isVisible(int row, int column) {
        if (isOutOfBounds(row, column)) return false;
        if ((span[row][column][CellSpan.COLUMN] < 1)
          ||(span[row][column][CellSpan.ROW]    < 1)) return false;
        return true;
      }  public void combine(int[] rows, int[] columns) {
        if (isOutOfBounds(rows, columns)) return;
        int    rowSpan  = rows.length;
        int columnSpan  = columns.length;
        int startRow    = rows[0];
        int startColumn = columns[0];
        for (int i=0;i<rowSpan;i++) {
          for (int j=0;j<columnSpan;j++) {
    if ((span[startRow +i][startColumn +j][CellSpan.COLUMN] != 1)
      ||(span[startRow +i][startColumn +j][CellSpan.ROW]    != 1)) {
      //System.out.println("can't combine");
      return ;
    }
          }
        }
        for (int i=0,ii=0;i<rowSpan;i++,ii--) {
          for (int j=0,jj=0;j<columnSpan;j++,jj--) {
    span[startRow +i][startColumn +j][CellSpan.COLUMN] = jj;
    span[startRow +i][startColumn +j][CellSpan.ROW]    = ii;
    //System.out.println("r " +ii +"  c " +jj);
          }
        }
        span[startRow][startColumn][CellSpan.COLUMN] = columnSpan;
        span[startRow][startColumn][CellSpan.ROW]    =    rowSpan;
        
      }  public void split(int row, int column) {
        if (isOutOfBounds(row, column)) return;
        int columnSpan = span[row][column][CellSpan.COLUMN];
        int    rowSpan = span[row][column][CellSpan.ROW];
        for (int i=0;i<rowSpan;i++) {
          for (int j=0;j<columnSpan;j++) {
    span[row +i][column +j][CellSpan.COLUMN] = 1;
    span[row +i][column +j][CellSpan.ROW]    = 1;
          }
        }
      }
      //
      // ColoredCell
      //
      public Color getForeground(int row, int column) {
        if (isOutOfBounds(row, column)) return null;
        return foreground[row][column];
      }
      public void setForeground(Color color, int row, int column) {
        if (isOutOfBounds(row, column)) return;
        foreground[row][column] = color;
      }
      public void setForeground(Color color, int[] rows, int[] columns) {
        if (isOutOfBounds(rows, columns)) return;
        setValues(foreground, color, rows, columns);
      }
      public Color getBackground(int row, int column) {
        if (isOutOfBounds(row, column)) return null;
        return background[row][column];
      }
      public void setBackground(Color color, int row, int column) {
        if (isOutOfBounds(row, column)) return;
        background[row][column] = color;
      }
      public void setBackground(Color color, int[] rows, int[] columns) {
        if (isOutOfBounds(rows, columns)) return;
        setValues(background, color, rows, columns);
      }
      //
      //
      // CellFont
      //
      public Font getFont(int row, int column) {
        if (isOutOfBounds(row, column)) return null;
        return font[row][column];
      }
      public void setFont(Font font, int row, int column) {
        if (isOutOfBounds(row, column)) return;
        this.font[row][column] = font;
      }
      public void setFont(Font font, int[] rows, int[] columns) {
        if (isOutOfBounds(rows, columns)) return;
        setValues(this.font, font, rows, columns);
      }
      //
      //
      // CellAttribute
      //
      public void addColumn() {
        int[][][] oldSpan = span;
        int numRows    = oldSpan.length;
        int numColumns = oldSpan[0].length;
        span = new int[numRows][numColumns + 1][2];
        System.arraycopy(oldSpan,0,span,0,numRows);
        for (int i=0;i<numRows;i++) {
          span[i][numColumns][CellSpan.COLUMN] = 1;
          span[i][numColumns][CellSpan.ROW]    = 1;
        }
      }  public void addRow() {
        int[][][] oldSpan = span;
        int numRows    = oldSpan.length;
        int numColumns = oldSpan[0].length;
        span = new int[numRows + 1][numColumns][2];
        System.arraycopy(oldSpan,0,span,0,numRows);
        for (int i=0;i<numColumns;i++) {
          span[numRows][i][CellSpan.COLUMN] = 1;
          span[numRows][i][CellSpan.ROW]    = 1;
        }
      }  public void insertRow(int row) {
        int[][][] oldSpan = span;
        int numRows    = oldSpan.length;
        int numColumns = oldSpan[0].length;
        span = new int[numRows + 1][numColumns][2];
        if (0 < row) {
          System.arraycopy(oldSpan,0,span,0,row-1);
        }
        System.arraycopy(oldSpan,0,span,row,numRows - row);
        for (int i=0;i<numColumns;i++) {
          span[row][i][CellSpan.COLUMN] = 1;
          span[row][i][CellSpan.ROW]    = 1;
        }
      }  public Dimension getSize() {
        return new Dimension(rowSize, columnSize);
      }  public void setSize(Dimension size) {
        columnSize = size.width;
        rowSize    = size.height;
        span = new int[rowSize][columnSize][2];   // 2: COLUMN,ROW
        foreground = new Color[rowSize][columnSize];
        background = new Color[rowSize][columnSize];
        font = new Font[rowSize][columnSize];
        initValue();
      }  /*
      public void changeAttribute(int row, int column, Object command) {
      }  public void changeAttribute(int[] rows, int[] columns, Object command) {
      }
      */
      protected boolean isOutOfBounds(int row, int column) {
        if ((row    < 0)||(rowSize    <= row)
          ||(column < 0)||(columnSize <= column)) {
          return true;
        }
        return false;
      }  protected boolean isOutOfBounds(int[] rows, int[] columns) {
        for (int i=0;i<rows.length;i++) {
          if ((rows[i] < 0)||(rowSize <= rows[i])) return true;
        }
        for (int i=0;i<columns.length;i++) {
          if ((columns[i] < 0)||(columnSize <= columns[i])) return true;
        }
        return false;
      }  protected void setValues(Object[][] target, Object value,
                               int[] rows, int[] columns) {
        for (int i=0;i<rows.length;i++) {
          int row = rows[i];
          for (int j=0;j<columns.length;j++) {
    int column = columns[j];
    target[row][column] = value;
          }
        }
      }
    }
      

  2.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;import java.awt.*;/**
     * @version 1.0 11/22/98
     */public interface CellAttribute {  public void addColumn();  public void addRow();  public void insertRow(int row);  public Dimension getSize();  public void setSize(Dimension size);
    }
      

  3.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;
    /**
     * @version 1.0 11/22/98
     */public interface CellSpan {
      public final int ROW    = 0;
      public final int COLUMN = 1;
      
      public int[] getSpan(int row, int column);
      public void setSpan(int[] span, int row, int column);
      
      public boolean isVisible(int row, int column);
      
      public void combine(int[] rows, int[] columns);
      public void split(int row, int column);}
      

  4.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;import java.util.*;
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import javax.swing.plaf.basic.*;
    import javax.swing.event.*;
    /**
     * @version 1.0 11/26/98
     */public class MultiSpanCellTable extends JTable {  public MultiSpanCellTable(TableModel model) {
        super(model);
        setUI(new MultiSpanCellTableUI());
        getTableHeader().setReorderingAllowed(false);
        setCellSelectionEnabled(true);
        setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
      }
      
      
      public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
        Rectangle sRect = super.getCellRect(row,column,includeSpacing);
        if ((row <0) || (column<0) ||
            (getRowCount() <= row) || (getColumnCount() <= column)) {
            return sRect;
        }
        CellSpan cellAtt = (CellSpan)((AttributiveCellTableModel)getModel()).getCellAttribute();
        if (! cellAtt.isVisible(row,column)) {
          int temp_row    = row;
          int temp_column = column;
          row    += cellAtt.getSpan(temp_row,temp_column)[CellSpan.ROW];
          column += cellAtt.getSpan(temp_row,temp_column)[CellSpan.COLUMN];      
        }
        int[] n = cellAtt.getSpan(row,column);    int index = 0;
        int columnMargin = getColumnModel().getColumnMargin();
        Rectangle cellFrame = new Rectangle();
        int aCellHeight = rowHeight + rowMargin;
        cellFrame.y = row * aCellHeight;
        cellFrame.height = n[CellSpan.ROW] * aCellHeight;
        
        Enumeration enumeration = getColumnModel().getColumns();
        while (enumeration.hasMoreElements()) {
          TableColumn aColumn = (TableColumn)enumeration.nextElement();
          cellFrame.width = aColumn.getWidth() + columnMargin;
          if (index == column) break;
          cellFrame.x += cellFrame.width;
          index++;
        }
        for (int i=0;i< n[CellSpan.COLUMN]-1;i++) {
          TableColumn aColumn = (TableColumn)enumeration.nextElement();
          cellFrame.width += aColumn.getWidth() + columnMargin;
        }
        
            if (!includeSpacing) {
          Dimension spacing = getIntercellSpacing();
          cellFrame.setBounds(cellFrame.x +      spacing.width/2,
      cellFrame.y +      spacing.height/2,
      cellFrame.width -  spacing.width,
      cellFrame.height - spacing.height);
        }
        return cellFrame;
      }
      
      
      private int[] rowColumnAtPoint(Point point) {
        int[] retValue = {-1,-1};
        int row = point.y / (rowHeight + rowMargin);
        if ((row <0)||(getRowCount() <= row)) return retValue;
        int column = getColumnModel().getColumnIndexAtX(point.x);    CellSpan cellAtt = (CellSpan)((AttributiveCellTableModel)getModel()).getCellAttribute();    if (cellAtt.isVisible(row,column)) {
          retValue[CellSpan.COLUMN] = column;
          retValue[CellSpan.ROW   ] = row;
          return retValue;
        }
        retValue[CellSpan.COLUMN] = column + cellAtt.getSpan(row,column)[CellSpan.COLUMN];
        retValue[CellSpan.ROW   ] = row + cellAtt.getSpan(row,column)[CellSpan.ROW];
        return retValue;
      }  
      public int rowAtPoint(Point point) {
        return rowColumnAtPoint(point)[CellSpan.ROW];
      }
      public int columnAtPoint(Point point) {
        return rowColumnAtPoint(point)[CellSpan.COLUMN];
      }
       
      public void columnSelectionChanged(ListSelectionEvent e) {
        repaint();
      }  public void valueChanged(ListSelectionEvent e) {
        int firstIndex = e.getFirstIndex();
        int  lastIndex = e.getLastIndex();
        if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
          repaint();
        }
        Rectangle dirtyRegion = getCellRect(firstIndex, 0, false);
        int numCoumns = getColumnCount();
        int index = firstIndex;
        for (int i=0;i<numCoumns;i++) {
          dirtyRegion.add(getCellRect(index, i, false));
        }
        index = lastIndex;
        for (int i=0;i<numCoumns;i++) {
          dirtyRegion.add(getCellRect(index, i, false));
        }
        repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
      }
     
    }
      

  5.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;import java.util.*;
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import javax.swing.plaf.basic.*;
    /**
     * @version 1.0 11/26/98
     */public class MultiSpanCellTableUI extends BasicTableUI {  public void paint(Graphics g, JComponent c) {
        Rectangle oldClipBounds = g.getClipBounds();
        Rectangle clipBounds    = new Rectangle(oldClipBounds);
        int tableWidth   = table.getColumnModel().getTotalColumnWidth();
        clipBounds.width = Math.min(clipBounds.width, tableWidth);
        g.setClip(clipBounds);    int firstIndex = table.rowAtPoint(new Point(0, clipBounds.y));
        int  lastIndex = table.getRowCount()-1;    Rectangle rowRect = new Rectangle(0,0,
          tableWidth, table.getRowHeight() + table.getRowMargin());
        rowRect.y = firstIndex*rowRect.height;    for (int index = firstIndex; index <= lastIndex; index++) {
          if (rowRect.intersects(clipBounds)) {
            //System.out.println();                  // debug
            //System.out.print("" + index +": ");    // row
    paintRow(g, index);
          }
          rowRect.y += rowRect.height;
        }
        g.setClip(oldClipBounds);
      }  private void paintRow(Graphics g, int row) {
        Rectangle rect = g.getClipBounds();
        boolean drawn  = false;
        
        AttributiveCellTableModel tableModel = (AttributiveCellTableModel)table.getModel();
        CellSpan cellAtt = (CellSpan)tableModel.getCellAttribute();
        int numColumns = table.getColumnCount();    for (int column = 0; column < numColumns; column++) {
          Rectangle cellRect = table.getCellRect(row,column,true);
          int cellRow,cellColumn;
          if (cellAtt.isVisible(row,column)) {
    cellRow    = row;
    cellColumn = column;
      //  System.out.print("   "+column+" ");  // debug
          } else {
    cellRow    = row + cellAtt.getSpan(row,column)[CellSpan.ROW];
    cellColumn = column + cellAtt.getSpan(row,column)[CellSpan.COLUMN];
      //  System.out.print("  ("+column+")");  // debug
          }
          if (cellRect.intersects(rect)) {
    drawn = true;
    paintCell(g, cellRect, cellRow, cellColumn);
          } else {
    if (drawn) break;
          } 
        }  }  private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
        int spacingHeight = table.getRowMargin();
        int spacingWidth  = table.getColumnModel().getColumnMargin();    Color c = g.getColor();
        g.setColor(table.getGridColor());
        g.drawRect(cellRect.x,cellRect.y,cellRect.width-1,cellRect.height-1);
        g.setColor(c);    cellRect.setBounds(cellRect.x + spacingWidth/2, cellRect.y + spacingHeight/2,
           cellRect.width - spacingWidth, cellRect.height - spacingHeight);    if (table.isEditing() && table.getEditingRow()==row &&
    table.getEditingColumn()==column) {
          Component component = table.getEditorComponent();
          component.setBounds(cellRect);
          component.validate();
        }
        else {
          TableCellRenderer renderer = table.getCellRenderer(row, column);
          Component component = table.prepareRenderer(renderer, row, column);      if (component.getParent() == null) {
    rendererPane.add(component);
          }
          rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
      cellRect.width, cellRect.height, true);
        }
      }    
    }
      

  6.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;import java.awt.*;
    /**
     * @version 1.0 11/22/98
     */public interface ColoredCell {
      
      public Color getForeground(int row, int column);
      public void setForeground(Color color, int row, int column);
      public void setForeground(Color color, int[] rows, int[] columns);  public Color getBackground(int row, int column);
      public void setBackground(Color color, int row, int column);
      public void setBackground(Color color, int[] rows, int[] columns);
    }
      

  7.   

    /*
     * (swing1.1beta3)
     * 
     */package jp.gr.java_conf.tame.swing.table;import java.awt.*;
    /**
     * @version 1.0 11/22/98
     */public interface CellFont {
      
      public Font getFont(int row, int column);
      public void setFont(Font font, int row, int column);
      public void setFont(Font font, int[] rows, int[] columns);
    }
      

  8.   

    MultiSpanCellTableExample.javaAttributiveCellTableModel.java
    DefaultCellAttribute.java
    CellAttribute.java
    ColoredCell.java
    CellFont.java
    CellSpan.java
    MultiSpanCellTable.java
    MultiSpanCellTableUI.java
      

  9.   

    package MultiSpanCell;import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import javax.swing.Box;
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JSeparator;
    import javax.swing.SwingConstants;public class MultiSpanCellTableExample
        extends JFrame {
      private AttributiveCellTableModel ml;
      private DefaultCellAttribute cellAtt;
      private MultiSpanCellTable table;
      
      public MultiSpanCellTableExample() {
        ml = new AttributiveCellTableModel(10, 6);
        cellAtt = ml.getCellAttribute();
        table = new MultiSpanCellTable(ml);
        JScrollPane scroll = new JScrollPane(table);    JButton b_one = new JButton("Combine");
        b_one.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            int[] columns = table.getSelectedColumns();
            int[] rows = table.getSelectedRows();
            cellAtt.combine(rows, columns);
            table.clearSelection();
            table.revalidate();
            table.repaint();
          }
        });
        JButton b_split = new JButton("Split");
        b_split.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            int column = table.getSelectedColumn();
            int row = table.getSelectedRow();
            cellAtt.split(row, column);
            table.clearSelection();
            table.revalidate();
            table.repaint();
          }
        });
        JButton dataButton = new JButton("dataButton");
        dataButton.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            System.out.println("ml.getValueAt(1,0)===" + ml.getValueAt(1, 0));
          }
        }
        );
        JPanel p_buttons = new JPanel();
        p_buttons.setLayout(new GridLayout(3, 1));
        p_buttons.add(b_one);
        p_buttons.add(b_split);
        p_buttons.add(dataButton);
        Box box = new Box(BoxLayout.X_AXIS);
        box.add(scroll);
        box.add(new JSeparator(SwingConstants.HORIZONTAL));
        box.add(p_buttons);
        getContentPane().add(box);
        setSize(400, 200);
        setVisible(true);
      }  public static void main(String[] args) {
        MultiSpanCellTableExample frame = new MultiSpanCellTableExample();
        frame.addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
            System.exit(0);
          }
        });
      }
    }
      

  10.   

    package MultiSpanCell;import java.awt.Dimension;
    import java.util.Enumeration;
    import java.util.Vector;
    import javax.swing.event.TableModelEvent;
    import javax.swing.table.DefaultTableModel;public class AttributiveCellTableModel extends DefaultTableModel {
      private DefaultCellAttribute cellAtt;  public AttributiveCellTableModel(int numRows, int numColumns) {
        Vector names = new Vector(numColumns);
        names.setSize(numColumns);
        setColumnIdentifiers(names);
        dataVector = new Vector();
        setNumRows(numRows);
        cellAtt = new DefaultCellAttribute(numRows,numColumns);
      }
      public AttributiveCellTableModel(Vector columnNames, int numRows) {
        setColumnIdentifiers(columnNames);
        dataVector = new Vector();
        setNumRows(numRows);
        cellAtt = new DefaultCellAttribute(numRows,columnNames.size());
      }
      public AttributiveCellTableModel(Object[] columnNames, int numRows) {
        this(convertToVector(columnNames), numRows);
      }
      public AttributiveCellTableModel(Vector data, Vector columnNames) {
        setDataVector(data, columnNames);
      }
      public AttributiveCellTableModel(Object[][] data, Object[] columnNames) {
        setDataVector(data, columnNames);
      }  public void setDataVector(Vector newData, Vector columnNames) {
        if (newData == null)throw new IllegalArgumentException(
            "setDataVector() - Null parameter");
        dataVector = (newData != null) ? newData : new Vector(0);
        columnIdentifiers = (columnNames != null) ? columnNames : new Vector(0);
        cellAtt = new DefaultCellAttribute(dataVector.size(),
                                           columnIdentifiers.size());
        newRowsAdded(new TableModelEvent(this, 0, getRowCount() - 1,
                                         TableModelEvent.ALL_COLUMNS,
                                         TableModelEvent.INSERT));
      }  public void addColumn(Object columnName, Vector columnData) {
        if (columnName == null)
          throw new IllegalArgumentException("addColumn() - null parameter");
        columnIdentifiers.addElement(columnName);
        int index = 0;
        Enumeration enumeration = dataVector.elements();
        while (enumeration.hasMoreElements()) {
          Object value;
          if ((columnData != null) && (index < columnData.size()))
      value = columnData.elementAt(index);
          else
    value = null;
          ((Vector)enumeration.nextElement()).addElement(value);
          index++;
        }
        cellAtt.addColumn();
        fireTableStructureChanged();
      }  public void addRow(Vector rowData) {
        Vector newData = null;
        if (rowData == null) {
          newData = new Vector(getColumnCount());
        }
        else {
          rowData.setSize(getColumnCount());
        }
        dataVector.addElement(newData);
        cellAtt.addRow();
        newRowsAdded(new TableModelEvent(this, getRowCount()-1, getRowCount()-1,
           TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
      }  public void insertRow(int row, Vector rowData) {
        if (rowData == null) {
          rowData = new Vector(getColumnCount());
        }
        else {
          rowData.setSize(getColumnCount());
        }
        dataVector.insertElementAt(rowData, row);
        cellAtt.insertRow(row);
        newRowsAdded(new TableModelEvent(this, row, row,
           TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
      }  public DefaultCellAttribute getCellAttribute() {
        return cellAtt;
      }  public void setCellAttribute(DefaultCellAttribute newCellAtt) {
        int numColumns = getColumnCount();
        int numRows    = getRowCount();
        if ((newCellAtt.getSize().width  != numColumns) ||
            (newCellAtt.getSize().height != numRows)) {
          newCellAtt.setSize(new Dimension(numRows, numColumns));
        }
        cellAtt = newCellAtt;
        fireTableDataChanged();
      }
    }
      

  11.   

    package MultiSpanCell;import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;public class DefaultCellAttribute{
      protected int rowSize;
      protected int columnSize;
      protected int[][][] span;                   // CellSpan
      protected Color[][] foreground;             // ColoredCell
      protected Color[][] background;             //
      protected Font[][]  font;                   // CellFont
      public final int ROW    = 0;
      public final int COLUMN = 1;  public DefaultCellAttribute() {
        this(1,1);
      }  public DefaultCellAttribute(int numRows, int numColumns) {
        setSize(new Dimension(numColumns, numRows));
      }  protected void initValue() {
        for(int i=0; i<span.length;i++) {
          for(int j=0; j<span[i].length; j++) {
    span[i][j][COLUMN] = 1;
    span[i][j][ROW]    = 1;
          }
        }
      }  public int[] getSpan(int row, int column) {
        if (isOutOfBounds(row, column)) {
          int[] ret_code = {1,1};
          return ret_code;
        }
        return span[row][column];
      }  public void setSpan(int[] span, int row, int column) {
        if (isOutOfBounds(row, column)) return;
        this.span[row][column] = span;
      }  public boolean isVisible(int row, int column) {
        if (isOutOfBounds(row, column)) return false;
        if ((span[row][column][COLUMN] < 1)
          ||(span[row][column][ROW]    < 1)) return false;
        return true;
      }  public void combine(int[] rows, int[] columns) {
        if (isOutOfBounds(rows, columns)) return;
        int    rowSpan  = rows.length;
        int columnSpan  = columns.length;
        int startRow    = rows[0];
        int startColumn = columns[0];
        for (int i=0;i<rowSpan;i++) {
          for (int j=0;j<columnSpan;j++) {
    if ((span[startRow +i][startColumn +j][COLUMN] != 1)
      ||(span[startRow +i][startColumn +j][ROW]    != 1)) {
      return ;
    }
          }
        }
        for (int i=0,ii=0;i<rowSpan;i++,ii--) {
          for (int j=0,jj=0;j<columnSpan;j++,jj--) {
    span[startRow +i][startColumn +j][COLUMN] = jj;
    span[startRow +i][startColumn +j][ROW]    = ii;
          }
        }
        span[startRow][startColumn][COLUMN] = columnSpan;
        span[startRow][startColumn][ROW]    =    rowSpan;  }  public void split(int row, int column) {
        if (isOutOfBounds(row, column)) return;
        int columnSpan = span[row][column][COLUMN];
        int    rowSpan = span[row][column][ROW];
        for (int i=0;i<rowSpan;i++) {
          for (int j=0;j<columnSpan;j++) {
    span[row +i][column +j][COLUMN] = 1;
    span[row +i][column +j][ROW]    = 1;
          }
        }
      }  public void addColumn() {
        int[][][] oldSpan = span;
        int numRows    = oldSpan.length;
        int numColumns = oldSpan[0].length;
        span = new int[numRows][numColumns + 1][2];
        System.arraycopy(oldSpan,0,span,0,numRows);
        for (int i=0;i<numRows;i++) {
          span[i][numColumns][COLUMN] = 1;
          span[i][numColumns][ROW]    = 1;
        }
      }  public void addRow() {
        int[][][] oldSpan = span;
        int numRows    = oldSpan.length;
        int numColumns = oldSpan[0].length;
        span = new int[numRows + 1][numColumns][2];
        System.arraycopy(oldSpan,0,span,0,numRows);
        for (int i=0;i<numColumns;i++) {
          span[numRows][i][COLUMN] = 1;
          span[numRows][i][ROW]    = 1;
        }
      }  public void insertRow(int row) {
        int[][][] oldSpan = span;
        int numRows    = oldSpan.length;
        int numColumns = oldSpan[0].length;
        span = new int[numRows + 1][numColumns][2];
        if (0 < row) {
          System.arraycopy(oldSpan,0,span,0,row-1);
        }
        System.arraycopy(oldSpan,0,span,row,numRows - row);
        for (int i=0;i<numColumns;i++) {
          span[row][i][COLUMN] = 1;
          span[row][i][ROW]    = 1;
        }
      }  public Dimension getSize() {
        return new Dimension(rowSize, columnSize);
      }  public void setSize(Dimension size) {
        columnSize = size.width;
        rowSize    = size.height;
        span = new int[rowSize][columnSize][2];   // 2: COLUMN,ROW
        foreground = new Color[rowSize][columnSize];
        background = new Color[rowSize][columnSize];
        font = new Font[rowSize][columnSize];
        initValue();
      }  protected boolean isOutOfBounds(int row, int column) {
        if ((row    < 0)||(rowSize    <= row)
          ||(column < 0)||(columnSize <= column)) {
          return true;
        }
        return false;
      }  protected boolean isOutOfBounds(int[] rows, int[] columns) {
        for (int i=0;i<rows.length;i++) {
          if ((rows[i] < 0)||(rowSize <= rows[i])) return true;
        }
        for (int i=0;i<columns.length;i++) {
          if ((columns[i] < 0)||(columnSize <= columns[i])) return true;
        }
        return false;
      }  protected void setValues(Object[][] target, Object value,
                               int[] rows, int[] columns) {
        for (int i=0;i<rows.length;i++) {
          int row = rows[i];
          for (int j=0;j<columns.length;j++) {
    int column = columns[j];
    target[row][column] = value;
          }
        }
      }
    }
      

  12.   

    package MultiSpanCell;import java.awt.Dimension;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.util.Enumeration;
    import javax.swing.JTable;
    import javax.swing.ListSelectionModel;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.table.TableColumn;
    import javax.swing.table.TableModel;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Graphics;
    import java.awt.Point;
    import java.awt.Rectangle;
    import javax.swing.JComponent;
    import javax.swing.plaf.basic.BasicTableUI;
    import javax.swing.table.TableCellRenderer;public class MultiSpanCellTable
        extends JTable {
      DefaultCellAttribute cellAtt;
      public MultiSpanCellTable(TableModel model) {
        super(model);
        setUI(new MultiSpanCellTableUI());
        getTableHeader().setReorderingAllowed(false);
        setCellSelectionEnabled(true);
        setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
      }  public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
        Rectangle sRect = super.getCellRect(row, column, includeSpacing);
        if ( (row < 0) || (column < 0) ||
            (getRowCount() <= row) || (getColumnCount() <= column)) {
          return sRect;
        }
        cellAtt = ( (AttributiveCellTableModel) getModel()).getCellAttribute();
        if (!cellAtt.isVisible(row, column)) {
          int temp_row = row;
          int temp_column = column;
          row += cellAtt.getSpan(temp_row, temp_column)[cellAtt.ROW];
          column += cellAtt.getSpan(temp_row, temp_column)[cellAtt.COLUMN];
        }
        int[] n = cellAtt.getSpan(row, column);    int index = 0;
        int columnMargin = getColumnModel().getColumnMargin();
        Rectangle cellFrame = new Rectangle();
        int aCellHeight = rowHeight + rowMargin;
        cellFrame.y = row * aCellHeight;
        cellFrame.height = n[cellAtt.ROW] * aCellHeight;    Enumeration enumeration = getColumnModel().getColumns();
        while (enumeration.hasMoreElements()) {
          TableColumn aColumn = (TableColumn) enumeration.nextElement();
          cellFrame.width = aColumn.getWidth() + columnMargin;
          if (index == column)break;
          cellFrame.x += cellFrame.width;
          index++;
        }
        for (int i = 0; i < n[cellAtt.COLUMN] - 1; i++) {
          TableColumn aColumn = (TableColumn) enumeration.nextElement();
          cellFrame.width += aColumn.getWidth() + columnMargin;
        }    if (!includeSpacing) {
          Dimension spacing = getIntercellSpacing();
          cellFrame.setBounds(cellFrame.x + spacing.width / 2,
                              cellFrame.y + spacing.height / 2,
                              cellFrame.width - spacing.width,
                              cellFrame.height - spacing.height);
        }
        return cellFrame;
      }  private int[] rowColumnAtPoint(Point point) {
        int[] retValue = {
             -1, -1};
        int row = point.y / (rowHeight + rowMargin);
        if ( (row < 0) || (getRowCount() <= row))return retValue;
        int column = getColumnModel().getColumnIndexAtX(point.x);    cellAtt = ( (AttributiveCellTableModel) getModel()).getCellAttribute();    if (cellAtt.isVisible(row, column)) {
          retValue[cellAtt.COLUMN] = column;
          retValue[cellAtt.ROW] = row;
          return retValue;
        }
        retValue[cellAtt.COLUMN] = column +
            cellAtt.getSpan(row, column)[cellAtt.COLUMN];
        retValue[cellAtt.ROW] = row + cellAtt.getSpan(row, column)[cellAtt.ROW];
        return retValue;
      }  public int rowAtPoint(Point point) {
        return rowColumnAtPoint(point)[cellAtt.ROW];
      }  public int columnAtPoint(Point point) {
        return rowColumnAtPoint(point)[cellAtt.COLUMN];
      }  public void columnSelectionChanged(ListSelectionEvent e) {
        repaint();
      }  public void valueChanged(ListSelectionEvent e) {
        int firstIndex = e.getFirstIndex();
        int lastIndex = e.getLastIndex();
        if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
          repaint();
        }
        Rectangle dirtyRegion = getCellRect(firstIndex, 0, false);
        int numCoumns = getColumnCount();
        int index = firstIndex;
        for (int i = 0; i < numCoumns; i++) {
          dirtyRegion.add(getCellRect(index, i, false));
        }
        index = lastIndex;
        for (int i = 0; i < numCoumns; i++) {
          dirtyRegion.add(getCellRect(index, i, false));
        }
        repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
      }
      
      
      private class MultiSpanCellTableUI extends BasicTableUI {
        DefaultCellAttribute cellAtt;
      
        public void paint(Graphics g, JComponent c) {
          Rectangle oldClipBounds = g.getClipBounds();
          Rectangle clipBounds    = new Rectangle(oldClipBounds);
          int tableWidth   = table.getColumnModel().getTotalColumnWidth();
          clipBounds.width = Math.min(clipBounds.width, tableWidth);
          g.setClip(clipBounds);
      
          int firstIndex = table.rowAtPoint(new Point(0, clipBounds.y));
          int  lastIndex = table.getRowCount()-1;
      
          Rectangle rowRect = new Rectangle(0,0,
            tableWidth, table.getRowHeight() + table.getRowMargin());
          rowRect.y = firstIndex*rowRect.height;
      
          for (int index = firstIndex; index <= lastIndex; index++) {
            if (rowRect.intersects(clipBounds)) {
              paintRow(g, index);
            }
            rowRect.y += rowRect.height;
          }
          g.setClip(oldClipBounds);
        }
      
        private void paintRow(Graphics g, int row) {
          Rectangle rect = g.getClipBounds();
          boolean drawn  = false;
      
          AttributiveCellTableModel tableModel = (AttributiveCellTableModel)table.getModel();
          cellAtt = tableModel.getCellAttribute();
          int numColumns = table.getColumnCount();
      
          for (int column = 0; column < numColumns; column++) {
            Rectangle cellRect = table.getCellRect(row,column,true);
            int cellRow,cellColumn;
            if (cellAtt.isVisible(row,column)) {
              cellRow    = row;
              cellColumn = column;
            } else {
              cellRow    = row + cellAtt.getSpan(row,column)[cellAtt.ROW];
              cellColumn = column + cellAtt.getSpan(row,column)[cellAtt.COLUMN];
            }
            if (cellRect.intersects(rect)) {
              drawn = true;
              paintCell(g, cellRect, cellRow, cellColumn);
            } else {
              if (drawn) break;
            }
          }
      
        }
      
        private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
          int spacingHeight = table.getRowMargin();
          int spacingWidth  = table.getColumnModel().getColumnMargin();
      
          Color c = g.getColor();
          g.setColor(table.getGridColor());
          g.drawRect(cellRect.x,cellRect.y,cellRect.width-1,cellRect.height-1);
          g.setColor(c);
      
          cellRect.setBounds(cellRect.x + spacingWidth/2, cellRect.y + spacingHeight/2,
                             cellRect.width - spacingWidth, cellRect.height - spacingHeight);
      
          if (table.isEditing() && table.getEditingRow()==row &&
              table.getEditingColumn()==column) {
            Component component = table.getEditorComponent();
            component.setBounds(cellRect);
            component.validate();
          }
          else {
            TableCellRenderer renderer = table.getCellRenderer(row, column);
            Component component = table.prepareRenderer(renderer, row, column);
      
            if (component.getParent() == null) {
              rendererPane.add(component);
            }
            rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
                                        cellRect.width, cellRect.height, true);
          }
        }
      }}