Java Swing写的支持合并单元格的JTable

 年前在网上参加了一个JavaSwing的招聘上机考试。招聘方要求开发一个类似EXCEL支持单元格合并的JTable。差不多用了5天的时间提交代码,最后被告知测试通过,我提出是否可做兼职,对方回复需要到上海做全职开发,最后也就放弃了。最近公司的一个项目中需要用到以前的代码,偶又重构了一次,设计思想来源于ListSelectionModel。

 

Java Swing写的支持合并单元格的JTable_第1张图片

GridBagModel:抽象模型接口。该接口用于描述表格中单元格的合并状态。
DefaultGridBagTableModel:GridBagModel的默认实现。
GridBagTable:继承自JTable的控制器。通过该类中的方法控制表格单元的合并和拆分。
GridBagTableUI:GridBagTable对应的UI。

TODO:(已合并)行、列的插入,删除操作对应的GridBagModel的修改,不过已留接口。

Java代码 复制代码  收藏代码
  1. package org.dxj.guitools.gridbagtable;   
  2. import java.awt.Component;   
  3. import java.awt.Point;   
  4. import java.awt.Rectangle;   
  5. import java.util.Enumeration;   
  6. import java.util.EventObject;   
  7.   
  8. import javax.swing.DefaultCellEditor;   
  9. import javax.swing.JTable;   
  10. import javax.swing.SwingUtilities;   
  11. import javax.swing.event.TableModelEvent;   
  12. import javax.swing.table.AbstractTableModel;   
  13. import javax.swing.table.TableColumn;   
  14. import javax.swing.table.TableColumnModel;   
  15.   
  16. /**  
  17.  * @author [email protected]  
  18.  */  
  19. public class GridBagTable extends JTable{   
  20.   
  21.     GridBagModel gridBagModel;   
  22.        
  23.     public GridBagModel getGridBagModel() {   
  24.         return gridBagModel;   
  25.     }   
  26.        
  27.     public void setGridBagModel(GridBagModel gridBagModel){   
  28.         if( gridBagModel != null && gridBagModel != this.gridBagModel )   
  29.             this.gridBagModel = gridBagModel;   
  30.     }   
  31.   
  32.     public GridBagTable(AbstractTableModel dm){   
  33.         super(dm);         
  34.         getTableHeader().setReorderingAllowed(false);   
  35.         gridBagModel = new DefaultGridBagTableModel(dm);           
  36.         getColumnModel().setColumnSelectionAllowed(true);   
  37.     }   
  38.        
  39.      private void updateSubComponentUI(Object componentShell) {   
  40.         if (componentShell == null) {   
  41.             return;   
  42.         }   
  43.         Component component = null;   
  44.         if (componentShell instanceof Component) {   
  45.             component = (Component)componentShell;   
  46.         }   
  47.         if (componentShell instanceof DefaultCellEditor) {   
  48.             component = ((DefaultCellEditor)componentShell).getComponent();   
  49.         }   
  50.   
  51.         if (component != null) {   
  52.             SwingUtilities.updateComponentTreeUI(component);   
  53.         }   
  54.     }   
  55.        
  56.     public void updateUI() {       
  57.         // Update the UIs of the cell renderers, cell editors and header renderers.   
  58.         TableColumnModel cm = getColumnModel();   
  59.         for(int column = 0; column < cm.getColumnCount(); column++) {   
  60.             TableColumn aColumn = cm.getColumn(column);   
  61.         updateSubComponentUI(aColumn.getCellRenderer());   
  62.             updateSubComponentUI(aColumn.getCellEditor());   
  63.         updateSubComponentUI(aColumn.getHeaderRenderer());   
  64.         }   
  65.   
  66.         // Update the UIs of all the default renderers.   
  67.         Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();   
  68.         while (defaultRenderers.hasMoreElements()) {   
  69.             updateSubComponentUI(defaultRenderers.nextElement());   
  70.         }   
  71.   
  72.         // Update the UIs of all the default editors.   
  73.         Enumeration defaultEditors = defaultEditorsByColumnClass.elements();   
  74.         while (defaultEditors.hasMoreElements()) {   
  75.             updateSubComponentUI(defaultEditors.nextElement());   
  76.         }   
  77.   
  78.         // Update the UI of the table header   
  79.         if (tableHeader != null && tableHeader.getParent() == null) {   
  80.             tableHeader.updateUI();   
  81.         }   
  82.         setUI(new GridBagTableUI());   
  83.     }   
  84.        
  85.     public Rectangle getGridCellRect(int row, int column, boolean includeSpacing){   
  86.         return super.getCellRect(row, column, includeSpacing);   
  87.     }   
  88.        
  89.     public Rectangle getCellRect(int row, int column, boolean includeSpacing) {        
  90.         Rectangle cellRect = super.getCellRect(row, column, includeSpacing);   
  91.         int cols = gridBagModel.getColumnGrid(row, column);   
  92.         TableColumnModel cm = getColumnModel();   
  93.         forint n=1; n
  94.             cellRect.width += cm.getColumn(column+n).getWidth();   
  95.         int rows = gridBagModel.getRowGrid(row, column);   
  96.         forint n=1; n
  97.             cellRect.height += getRowHeight(row+n);   
  98.         return cellRect;            
  99.     }   
  100.        
  101.     public void tableChanged(TableModelEvent e){   
  102.         super.tableChanged(e);   
  103.         //TODO   
  104.     }   
  105.        
  106.     public boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn){   
  107.         if( gridBagModel.mergeCells(startRow, endRow, startColumn, endColumn)){   
  108.             repaint();   
  109.             return true;   
  110.         }      
  111.         return false;   
  112.     }   
  113.         
  114.     public boolean mergeCells(int[] rows, int[] columns){   
  115.         if( gridBagModel.mergeCells(rows, columns)){   
  116.             repaint();   
  117.             return true;   
  118.         }      
  119.         return false;   
  120.     }   
  121.        
  122.     public boolean spliteCellAt(int row, int column){   
  123.         if( gridBagModel.spliteCellAt(row, column)){   
  124.             repaint();   
  125.             return true;   
  126.         }   
  127.         return false;   
  128.     }   
  129.        
  130.     public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {   
  131.         if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )   
  132.             super.changeSelection(rowIndex, columnIndex, toggle, extend);   
  133.         Point p;   
  134.         forint row = rowIndex; row >= 0; row-- ){   
  135.             forint col = columnIndex; col >= 0; col-- ){   
  136.                 p = gridBagModel.getGrid(row, col);   
  137.                 //p = ((Point)((Vector)rowVector.get(row)).get(col));   
  138.                 if( col + p.x > columnIndex && row + p.y > rowIndex){   
  139.                     rowIndex = row;   
  140.                     columnIndex = col;   
  141.                     break;   
  142.                 }   
  143.             }   
  144.         }      
  145.         super.changeSelection(rowIndex, columnIndex, toggle, extend);   
  146.         repaint();   
  147.     }   
  148.        
  149.     public boolean editCellAt(int rowIndex, int columnIndex, EventObject e){   
  150.         if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )   
  151.             return super.editCellAt(rowIndex, columnIndex, e);      
  152.         Point p;   
  153.         forint row = rowIndex; row >= 0; row-- ){   
  154.             forint col = columnIndex; col >= 0; col-- ){   
  155.                 p = gridBagModel.getGrid(row, col);   
  156.                 if( col + p.x > columnIndex && row + p.y > rowIndex){   
  157.                     rowIndex = row;   
  158.                     columnIndex = col;   
  159.                     break;   
  160.                 }   
  161.             }   
  162.         }          
  163.         return super.editCellAt(rowIndex, columnIndex, e);           
  164.     }   
  165. }  
package org.dxj.guitools.gridbagtable;
import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Enumeration;
import java.util.EventObject;

import javax.swing.DefaultCellEditor;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

/**
 * @author [email protected]
 */
public class GridBagTable extends JTable{

	GridBagModel gridBagModel;
	
	public GridBagModel getGridBagModel() {
		return gridBagModel;
	}
	
	public void setGridBagModel(GridBagModel gridBagModel){
		if( gridBagModel != null && gridBagModel != this.gridBagModel )
			this.gridBagModel = gridBagModel;
	}

	public GridBagTable(AbstractTableModel dm){
		super(dm);		
		getTableHeader().setReorderingAllowed(false);
		gridBagModel = new DefaultGridBagTableModel(dm);		
		getColumnModel().setColumnSelectionAllowed(true);
	}
	
	 private void updateSubComponentUI(Object componentShell) {
        if (componentShell == null) {
            return;
        }
        Component component = null;
        if (componentShell instanceof Component) {
            component = (Component)componentShell;
        }
        if (componentShell instanceof DefaultCellEditor) {
            component = ((DefaultCellEditor)componentShell).getComponent();
        }

        if (component != null) {
            SwingUtilities.updateComponentTreeUI(component);
        }
    }
	
	public void updateUI() {	
        // Update the UIs of the cell renderers, cell editors and header renderers.
        TableColumnModel cm = getColumnModel();
        for(int column = 0; column < cm.getColumnCount(); column++) {
            TableColumn aColumn = cm.getColumn(column);
	    updateSubComponentUI(aColumn.getCellRenderer());
            updateSubComponentUI(aColumn.getCellEditor());
	    updateSubComponentUI(aColumn.getHeaderRenderer());
        }

        // Update the UIs of all the default renderers.
        Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
        while (defaultRenderers.hasMoreElements()) {
            updateSubComponentUI(defaultRenderers.nextElement());
        }

        // Update the UIs of all the default editors.
        Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
        while (defaultEditors.hasMoreElements()) {
            updateSubComponentUI(defaultEditors.nextElement());
        }

        // Update the UI of the table header
        if (tableHeader != null && tableHeader.getParent() == null) {
            tableHeader.updateUI();
        }
        setUI(new GridBagTableUI());
    }
	
	public Rectangle getGridCellRect(int row, int column, boolean includeSpacing){
		return super.getCellRect(row, column, includeSpacing);
	}
	
	public Rectangle getCellRect(int row, int column, boolean includeSpacing) {		
		Rectangle cellRect = super.getCellRect(row, column, includeSpacing);
		int cols = gridBagModel.getColumnGrid(row, column);
		TableColumnModel cm = getColumnModel();
		for( int n=1; n= 0; row-- ){
			for( int col = columnIndex; col >= 0; col-- ){
				p = gridBagModel.getGrid(row, col);
				//p = ((Point)((Vector)rowVector.get(row)).get(col));
				if( col + p.x > columnIndex && row + p.y > rowIndex){
					rowIndex = row;
					columnIndex = col;
					break;
				}
    		}
		}  	
    	super.changeSelection(rowIndex, columnIndex, toggle, extend);
    	repaint();
    }
    
    public boolean editCellAt(int rowIndex, int columnIndex, EventObject e){
    	if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )
    		return super.editCellAt(rowIndex, columnIndex, e);   
		Point p;
		for( int row = rowIndex; row >= 0; row-- ){
			for( int col = columnIndex; col >= 0; col-- ){
				p = gridBagModel.getGrid(row, col);
				if( col + p.x > columnIndex && row + p.y > rowIndex){
					rowIndex = row;
					columnIndex = col;
					break;
				}
    		}
		}   	
    	return super.editCellAt(rowIndex, columnIndex, e);        
    }
}
 
Java代码 复制代码  收藏代码
  1. package org.dxj.guitools.gridbagtable;   
  2.   
  3. import java.awt.Point;   
  4.   
  5. public interface GridBagModel {   
  6.     //格子处于正常状态   
  7.     int DEFAULT = 0;   
  8.     //格子合并了其他的格子   
  9.     int MERGE = 1;   
  10.     //格子被其他格子合并   
  11.     int COVERED = -1;   
  12.        
  13.     /**  
  14.      * @param row 行  
  15.      * @param column 列  
  16.      * @return 该单元格在行、列的跨度  
  17.      */  
  18.     Point getGrid(int row, int column);   
  19.        
  20.     /**  
  21.      * 在Y轴方向的跨度  
  22.      * @param row  
  23.      * @param column  
  24.      * @return  
  25.      */  
  26.     int getRowGrid(int row, int column);   
  27.        
  28.     /**  
  29.      * 在X轴方向的跨度  
  30.      * @param row  
  31.      * @param column  
  32.      * @return  
  33.      */  
  34.     int getColumnGrid(int row, int column);   
  35.   
  36.     /**  
  37.      * @param rows 行集合  
  38.      * @param columns 列集合  
  39.      * @return 单元格集合是否可以合并在一起  
  40.      */  
  41.     boolean canMergeCells(int[] rows, int[] columns);   
  42.        
  43.     /**  
  44.      * 判断该单元格状态  
  45.      * @param row  
  46.      * @param column  
  47.      * @return MERGE|DEFAULT|COVERED  
  48.      */  
  49.     int getCellState(int row, int column);   
  50.        
  51.     /**  
  52.      * 将单元格集合合并  
  53.      * @param startRow 开始行  
  54.      * @param endRow 结束行  
  55.      * @param startColumn 开始列  
  56.      * @param endColumn 结束列  
  57.      * @return 是否合并成功  
  58.      */  
  59.     boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn);   
  60.        
  61.     /**  
  62.      * 将单元格集合合并  
  63.      * @param rows 行集合  
  64.      * @param columns 列集合  
  65.      * @return 是否合并成功  
  66.      */  
  67.     boolean mergeCells(int[] rows, int[] columns);   
  68.        
  69.     /**  
  70.      * 拆分单元格  
  71.      * @param row 行  
  72.      * @param column 列  
  73.      * @return 是否拆分成功  
  74.      */  
  75.     boolean spliteCellAt(int row, int column);   
  76.        
  77.     /**  
  78.      * 清除 所有合并  
  79.      */  
  80.     void clearMergence();   
  81. }  
package org.dxj.guitools.gridbagtable;

import java.awt.Point;

public interface GridBagModel {
	//格子处于正常状态
	int DEFAULT = 0;
	//格子合并了其他的格子
	int MERGE = 1;
	//格子被其他格子合并
	int COVERED = -1;
	
	/**
	 * @param row 行
	 * @param column 列
	 * @return 该单元格在行、列的跨度
	 */
	Point getGrid(int row, int column);
	
	/**
	 * 在Y轴方向的跨度
	 * @param row
	 * @param column
	 * @return
	 */
	int getRowGrid(int row, int column);
	
	/**
	 * 在X轴方向的跨度
	 * @param row
	 * @param column
	 * @return
	 */
	int getColumnGrid(int row, int column);

	/**
	 * @param rows 行集合
	 * @param columns 列集合
	 * @return 单元格集合是否可以合并在一起
	 */
	boolean canMergeCells(int[] rows, int[] columns);
	
	/**
	 * 判断该单元格状态
	 * @param row
	 * @param column
	 * @return MERGE|DEFAULT|COVERED
	 */
	int getCellState(int row, int column);
	
	/**
	 * 将单元格集合合并
	 * @param startRow 开始行
	 * @param endRow 结束行
	 * @param startColumn 开始列
	 * @param endColumn 结束列
	 * @return 是否合并成功
	 */
	boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn);
	
	/**
	 * 将单元格集合合并
	 * @param rows 行集合
	 * @param columns 列集合
	 * @return 是否合并成功
	 */
	boolean mergeCells(int[] rows, int[] columns);
	
	/**
	 * 拆分单元格
	 * @param row 行
	 * @param column 列
	 * @return 是否拆分成功
	 */
	boolean spliteCellAt(int row, int column);
	
	/**
	 * 清除 所有合并
	 */
	void clearMergence();
}
 
Java代码 复制代码  收藏代码
  1. package org.dxj.guitools.gridbagtable;   
  2.   
  3. import java.awt.Point;   
  4. import java.util.Arrays;   
  5. import java.util.List;   
  6. import java.util.Vector;   
  7.   
  8. import javax.swing.event.TableModelEvent;   
  9. import javax.swing.event.TableModelListener;   
  10. import javax.swing.table.AbstractTableModel;   
  11.   
  12. public class DefaultGridBagTableModel implements GridBagModel, TableModelListener{   
  13.     protected AbstractTableModel model;   
  14.     protected List> gridInfo;   
  15.        
  16.     DefaultGridBagTableModel(AbstractTableModel model){   
  17.         gridInfo = new Vector>();   
  18.         setTableModel(model);   
  19.     }   
  20.        
  21.     public void setTableModel(AbstractTableModel model){   
  22.         if( model != null && model != this.model ){   
  23.             ifthis.model != null )   
  24.                 this.model.removeTableModelListener(this);   
  25.             //防止多次添加监听器   
  26.             model.removeTableModelListener(this);   
  27.             model.addTableModelListener(this);   
  28.             this.model = model;   
  29.             clearMergence();   
  30.         }   
  31.     }   
  32.        
  33.     public void clearMergence(){   
  34.         if( gridInfo == null  )   
  35.             gridInfo = new Vector>();   
  36.         else  
  37.             gridInfo.clear();   
  38.            
  39.         if( model == null )   
  40.             return;   
  41.            
  42.         //初始化,每个格子占的格子数为(1,1);   
  43.         for(int row=model.getRowCount(); --row>=0;){   
  44.             List infos = new Vector();   
  45.             gridInfo.add(infos);   
  46.             for(int col=model.getColumnCount(); --col>=0;){   
  47.                 infos.add(getDefaultPoint());   
  48.             }   
  49.         }   
  50.     }   
  51.        
  52.     public Point getDefaultPoint(){   
  53.         return new Point(1,1);   
  54.     }   
  55.        
  56.     @Override  
  57.     public boolean canMergeCells(int[] rows, int[] columns) {   
  58.         if( rows == null || columns == null ) return false;   
  59.         Arrays.sort(rows);   
  60.         for(int index=0; index1; index++){   
  61.             if( rows[index+1] - rows[index] > 1 )   
  62.                 return false;   
  63.         }   
  64.         Arrays.sort(columns);   
  65.         for(int index=0; index1; index++){   
  66.             if( columns[index+1] - columns[index] > 1 )   
  67.                 return false;   
  68.         }   
  69.         return true;   
  70.     }   
  71.        
  72.     @Override  
  73.     public int getCellState(int row, int column) {   
  74.         Point grid = getGrid(row, column);   
  75.         if( grid == null ) return DEFAULT;   
  76.         if( grid.x>1 || grid.y>1 )   
  77.             return MERGE;   
  78.         if( grid.x<=0 || grid.y<=0 )   
  79.             return COVERED;   
  80.         return DEFAULT;   
  81.     }   
  82.   
  83.     @Override  
  84.     public int getColumnGrid(int row, int column) {   
  85.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
  86.             List gridRow = gridInfo.get(row);   
  87.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
  88.                 Point point = gridRow.get(column);   
  89.                 if( point != null )   
  90.                     return point.x;   
  91.             }      
  92.         }   
  93.         return 1;   
  94.     }   
  95.   
  96.     @Override  
  97.     public Point getGrid(int row, int column) {   
  98.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
  99.             List gridRow = gridInfo.get(row);   
  100.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
  101.                 return gridRow.get(column);   
  102.             }      
  103.         }   
  104.         return getDefaultPoint();   
  105.     }   
  106.   
  107.     @Override  
  108.     public int getRowGrid(int row, int column) {   
  109.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
  110.             List gridRow = gridInfo.get(row);   
  111.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
  112.                 Point point = gridRow.get(column);   
  113.                 if( point != null )   
  114.                     return point.y;   
  115.             }      
  116.         }   
  117.         return 1;   
  118.     }   
  119.   
  120.     protected boolean setGrid(int row, int column, Point grid) {   
  121.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
  122.             List gridRow = gridInfo.get(row);   
  123.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
  124.                 Point point = gridRow.get(column);   
  125.                 if( point != null ){   
  126.                     point.setLocation(grid);   
  127.                 }   
  128.                 else{   
  129.                     gridRow.set(column, grid.getLocation());   
  130.                 }   
  131.                 return true;   
  132.             }      
  133.         }   
  134.         return false;   
  135.     }   
  136.   
  137.     @Override  
  138.     public boolean spliteCellAt(int row, int column) {   
  139.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
  140.             List gridRow = gridInfo.get(row);   
  141.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
  142.                 Point point = gridRow.get(column);   
  143.                 if( point != null ){   
  144.                     point = point.getLocation();   
  145.                     for(int a=0; a
  146.                         for(int b=0; b
  147.                             setGrid(row+a, column+b, getDefaultPoint());   
  148.                         }   
  149.                     }   
  150.                 }   
  151.                 else{   
  152.                     gridRow.set(column, getDefaultPoint());   
  153.                 }   
  154.                 return true;   
  155.             }      
  156.         }   
  157.         return false;   
  158.     }   
  159.        
  160.     @Override  
  161.     /**  
  162.      * table中发生行的添加和删除的时候需要修改该模型  
  163.      */  
  164.     public void tableChanged(TableModelEvent e) {   
  165.         //TODO   
  166.     }   
  167.        
  168.     @Override  
  169.     public boolean mergeCells(int[] rows, int[] columns) {   
  170.         if( !canMergeCells(rows, columns) )   
  171.             return false;   
  172.         Arrays.sort(rows);   
  173.         Arrays.sort(columns);   
  174.         return mergeCells(rows[0],rows[rows.length-1],columns[0],columns[columns.length-1]);   
  175.     }   
  176.   
  177.     @Override  
  178.     public boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn) {   
  179.         setGrid(startRow, startColumn, new Point(endColumn-startColumn+1, endRow-startRow+1));    
  180.         for(int row=startRow; row<=endRow; row++){   
  181.             for(int col=startColumn; col<=endColumn; col++){   
  182.                 if(row==startRow&&col==startColumn)   
  183.                     continue;   
  184.                 else  
  185.                     setGrid(row, col, new Point(COVERED,COVERED));    
  186.             }   
  187.         }   
  188.         return true;   
  189.     }   
  190.        
  191.     public String toString(){   
  192.         if( gridInfo == null )   
  193.             return "";   
  194.         StringBuffer sb = new StringBuffer();   
  195.         for(List rowInfo : gridInfo ){   
  196.             for(Point grid : rowInfo){   
  197.                 sb.append("["+grid.x+","+grid.y+"], ");   
  198.             }   
  199.             sb.append("\n");   
  200.         }   
  201.         return sb.toString();   
  202.     }   
  203. }  
package org.dxj.guitools.gridbagtable;

import java.awt.Point;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;

public class DefaultGridBagTableModel implements GridBagModel, TableModelListener{
	protected AbstractTableModel model;
	protected List> gridInfo;
	
	DefaultGridBagTableModel(AbstractTableModel model){
		gridInfo = new Vector>();
		setTableModel(model);
	}
	
	public void setTableModel(AbstractTableModel model){
		if( model != null && model != this.model ){
			if( this.model != null )
				this.model.removeTableModelListener(this);
			//防止多次添加监听器
			model.removeTableModelListener(this);
			model.addTableModelListener(this);
			this.model = model;
			clearMergence();
		}
	}
	
	public void clearMergence(){
		if( gridInfo == null  )
			gridInfo = new Vector>();
		else
			gridInfo.clear();
		
		if( model == null )
			return;
		
		//初始化,每个格子占的格子数为(1,1);
		for(int row=model.getRowCount(); --row>=0;){
			List infos = new Vector();
			gridInfo.add(infos);
			for(int col=model.getColumnCount(); --col>=0;){
				infos.add(getDefaultPoint());
			}
		}
	}
	
	public Point getDefaultPoint(){
		return new Point(1,1);
	}
	
	@Override
	public boolean canMergeCells(int[] rows, int[] columns) {
		if( rows == null || columns == null ) return false;
		Arrays.sort(rows);
		for(int index=0; index 1 )
				return false;
		}
		Arrays.sort(columns);
		for(int index=0; index 1 )
				return false;
		}
		return true;
	}
	
	@Override
	public int getCellState(int row, int column) {
		Point grid = getGrid(row, column);
		if( grid == null ) return DEFAULT;
		if( grid.x>1 || grid.y>1 )
			return MERGE;
		if( grid.x<=0 || grid.y<=0 )
			return COVERED;
		return DEFAULT;
	}

	@Override
	public int getColumnGrid(int row, int column) {
		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
			List gridRow = gridInfo.get(row);
			if( gridRow != null && column >=0 && column < gridRow.size() ){
				Point point = gridRow.get(column);
				if( point != null )
					return point.x;
			}	
		}
		return 1;
	}

	@Override
	public Point getGrid(int row, int column) {
		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
			List gridRow = gridInfo.get(row);
			if( gridRow != null && column >=0 && column < gridRow.size() ){
				return gridRow.get(column);
			}	
		}
		return getDefaultPoint();
	}

	@Override
	public int getRowGrid(int row, int column) {
		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
			List gridRow = gridInfo.get(row);
			if( gridRow != null && column >=0 && column < gridRow.size() ){
				Point point = gridRow.get(column);
				if( point != null )
					return point.y;
			}	
		}
		return 1;
	}

	protected boolean setGrid(int row, int column, Point grid) {
		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
			List gridRow = gridInfo.get(row);
			if( gridRow != null && column >=0 && column < gridRow.size() ){
				Point point = gridRow.get(column);
				if( point != null ){
					point.setLocation(grid);
				}
				else{
					gridRow.set(column, grid.getLocation());
				}
				return true;
			}	
		}
		return false;
	}

	@Override
	public boolean spliteCellAt(int row, int column) {
		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
			List gridRow = gridInfo.get(row);
			if( gridRow != null && column >=0 && column < gridRow.size() ){
				Point point = gridRow.get(column);
				if( point != null ){
					point = point.getLocation();
					for(int a=0; a rowInfo : gridInfo ){
			for(Point grid : rowInfo){
				sb.append("["+grid.x+","+grid.y+"], ");
			}
			sb.append("\n");
		}
		return sb.toString();
	}
}
 
Java代码 复制代码  收藏代码
  1. package org.dxj.guitools.gridbagtable;   
  2.   
  3. import java.awt.Color;   
  4. import java.awt.Component;   
  5. import java.awt.Dimension;   
  6. import java.awt.Graphics;   
  7. import java.awt.Point;   
  8. import java.awt.Rectangle;   
  9. import java.util.Enumeration;   
  10.   
  11. import javax.swing.BorderFactory;   
  12. import javax.swing.JComponent;   
  13. import javax.swing.JTable;   
  14. import javax.swing.UIManager;   
  15. import javax.swing.plaf.basic.BasicTableUI;   
  16. import javax.swing.table.JTableHeader;   
  17. import javax.swing.table.TableCellRenderer;   
  18. import javax.swing.table.TableColumn;   
  19. import javax.swing.table.TableColumnModel;   
  20.   
  21. public class GridBagTableUI extends BasicTableUI   
  22. {   
  23.     public Dimension getPreferredSize(JComponent c) {   
  24.         long width = 0;   
  25.         Enumeration enumeration = table.getColumnModel().getColumns();   
  26.         while (enumeration.hasMoreElements()) {   
  27.             TableColumn aColumn = (TableColumn)enumeration.nextElement();   
  28.             width = width + aColumn.getPreferredWidth();   
  29.         }   
  30.         return createTableSize(width);   
  31.     }   
  32.        
  33.     private Dimension createTableSize(long width) {   
  34.         int height = 0;   
  35.         int rowCount = table.getRowCount();   
  36.         if (rowCount > 0 && table.getColumnCount() > 0) {   
  37.             Rectangle r = table.getCellRect(rowCount-10true);   
  38.             height = r.y + r.height;   
  39.         }   
  40.         // Width is always positive. The call to abs() is a workaround for   
  41.         // a bug in the 1.1.6 JIT on Windows.   
  42.         long tmp = Math.abs(width);   
  43.             if (tmp > Integer.MAX_VALUE) {   
  44.                 tmp = Integer.MAX_VALUE;   
  45.             }   
  46.         return new Dimension((int)tmp, height);   
  47.         }   
  48.        
  49.     public void paint(Graphics g, JComponent c) {   
  50.         Rectangle clip = g.getClipBounds();   
  51.   
  52.         Rectangle bounds = table.getBounds();   
  53.         // account for the fact that the graphics has already been translated   
  54.         // into the table's bounds   
  55.         bounds.x = bounds.y = 0;   
  56.   
  57.     if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||   
  58.                 // this check prevents us from painting the entire table   
  59.                 // when the clip doesn't intersect our bounds at all   
  60.                 !bounds.intersects(clip)) {   
  61.   
  62.             paintDropLines(g);   
  63.         return;   
  64.     }   
  65.   
  66.         boolean ltr = table.getComponentOrientation().isLeftToRight();   
  67.   
  68.     Point upperLeft = clip.getLocation();   
  69.         if (!ltr) {   
  70.             upperLeft.x++;   
  71.         }   
  72.   
  73.     Point lowerRight = new Point(clip.x + clip.width - (ltr ? 1 : 0),   
  74.                                      clip.y + clip.height);   
  75.   
  76.         int rMin = table.rowAtPoint(upperLeft);   
  77.         int rMax = table.rowAtPoint(lowerRight);   
  78.         // This should never happen (as long as our bounds intersect the clip,   
  79.         // which is why we bail above if that is the case).   
  80.         if (rMin == -1) {   
  81.         rMin = 0;   
  82.         }   
  83.         // If the table does not have enough rows to fill the view we'll get -1.   
  84.         // (We could also get -1 if our bounds don't intersect the clip,   
  85.         // which is why we bail above if that is the case).   
  86.         // Replace this with the index of the last row.   
  87.         if (rMax == -1) {   
  88.         rMax = table.getRowCount()-1;   
  89.         }   
  90.   
  91.         int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);    
  92.         int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);           
  93.         // This should never happen.   
  94.         if (cMin == -1) {   
  95.         cMin = 0;   
  96.         }   
  97.     // If the table does not have enough columns to fill the view we'll get -1.   
  98.         // Replace this with the index of the last column.   
  99.         if (cMax == -1) {   
  100.         cMax = table.getColumnCount()-1;   
  101.         }   
  102.   
  103.         // Paint the grid.   
  104.         //paintGrid(g, rMin, rMax, cMin, cMax);   
  105.   
  106.         // Paint the cells.   
  107.     paintCells(g, rMin, rMax, cMin, cMax);   
  108.   
  109.         paintDropLines(g);   
  110.     }   
  111.        
  112.     private void paintDropLines(Graphics g) {   
  113.         JTable.DropLocation loc = table.getDropLocation();   
  114.         if (loc == null) {   
  115.             return;   
  116.         }   
  117.   
  118.         Color color = UIManager.getColor("Table.dropLineColor");   
  119.         Color shortColor = UIManager.getColor("Table.dropLineShortColor");   
  120.         if (color == null && shortColor == null) {   
  121.             return;   
  122.         }   
  123.   
  124.         Rectangle rect;   
  125.   
  126.         rect = getHDropLineRect(loc);   
  127.         if (rect != null) {   
  128.             int x = rect.x;   
  129.             int w = rect.width;   
  130.             if (color != null) {   
  131.                 extendRect(rect, true);   
  132.                 g.setColor(color);   
  133.                 g.fillRect(rect.x, rect.y, rect.width, rect.height);   
  134.             }   
  135.             if (!loc.isInsertColumn() && shortColor != null) {   
  136.                 g.setColor(shortColor);   
  137.                 g.fillRect(x, rect.y, w, rect.height);   
  138.             }   
  139.         }   
  140.   
  141.         rect = getVDropLineRect(loc);   
  142.         if (rect != null) {   
  143.             int y = rect.y;   
  144.             int h = rect.height;   
  145.             if (color != null) {   
  146.                 extendRect(rect, false);   
  147.                 g.setColor(color);   
  148.                 g.fillRect(rect.x, rect.y, rect.width, rect.height);   
  149.             }   
  150.             if (!loc.isInsertRow() && shortColor != null) {   
  151.                 g.setColor(shortColor);   
  152.                 g.fillRect(rect.x, y, rect.width, h);   
  153.             }   
  154.         }   
  155.     }   
  156.        
  157.     /*  
  158.      * Paints the grid lines within aRect, using the grid  
  159.      * color set with setGridColor. Paints vertical lines  
  160.      * if getShowVerticalLines() returns true and paints  
  161.      * horizontal lines if getShowHorizontalLines()  
  162.      * returns true.  
  163.      */  
  164.     private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {   
  165.         g.setColor(table.getGridColor());   
  166.   
  167.         Rectangle minCell = table.getCellRect(rMin, cMin, true);   
  168.         Rectangle maxCell = table.getCellRect(rMax, cMax, true);   
  169.         Rectangle damagedArea = minCell.union( maxCell );   
  170.   
  171.         if (table.getShowHorizontalLines()) {   
  172.             int tableWidth = damagedArea.x + damagedArea.width;   
  173.             int y = damagedArea.y;   
  174.             for (int row = rMin; row <= rMax; row++) {   
  175.                 y += table.getRowHeight(row);   
  176.                 g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);   
  177.             }   
  178.         }   
  179.         if (table.getShowVerticalLines()) {   
  180.             TableColumnModel cm = table.getColumnModel();   
  181.             int tableHeight = damagedArea.y + damagedArea.height;   
  182.             int x;   
  183.             if (table.getComponentOrientation().isLeftToRight()) {   
  184.                 x = damagedArea.x;   
  185.                 for (int column = cMin; column <= cMax; column++) {   
  186.                     int w = cm.getColumn(column).getWidth();   
  187.                     x += w;   
  188.                     g.drawLine(x - 10, x - 1, tableHeight - 1);   
  189.                 }   
  190.             } else {   
  191.                 x = damagedArea.x;   
  192.                 for (int column = cMax; column >= cMin; column--) {   
  193.                     int w = cm.getColumn(column).getWidth();   
  194.                     x += w;   
  195.                     g.drawLine(x - 10, x - 1, tableHeight - 1);   
  196.                 }   
  197.             }   
  198.         }   
  199.     }   
  200.        
  201.     private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {   
  202.         JTableHeader header = table.getTableHeader();   
  203.         TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();   
  204.   
  205.         TableColumnModel cm = table.getColumnModel();   
  206.         int columnMargin = cm.getColumnMargin();   
  207.             Rectangle cellRect;   
  208.         TableColumn aColumn;   
  209.         int columnWidth;   
  210.         if (table.getComponentOrientation().isLeftToRight()) {   
  211.             for(int row = rMin; row <= rMax; row++) {   
  212.                 if( table instanceof GridBagTable )   
  213.                     cellRect = ((GridBagTable)table).getGridCellRect(row, cMin, false);   
  214.                 else  
  215.                     cellRect = table.getCellRect(row, cMin, false);   
  216.                 for(int column = cMin; column <= cMax; column++) {   
  217.                     aColumn = cm.getColumn(column);   
  218.                     columnWidth = aColumn.getWidth();                                    
  219.                     //TODO   
  220.                     cellRect.width = columnWidth - columnMargin;   
  221.                     int oldHeight = cellRect.height;   
  222.                     if( table instanceof GridBagTable ){   
  223.                         if(((GridBagTable)table).getGridBagModel().getCellState( row, column) == GridBagModel.COVERED ) {   
  224.                             cellRect.width = 0;   
  225.                             cellRect.height = 0;   
  226.                         }   
  227.                         else{   
  228.                             int h = ((GridBagTable)table).getGridBagModel().getColumnGrid(row, column);   
  229.                             if( h >1 ){   
  230.                                 forint n=1; n
  231.                                     cellRect.width += cm.getColumn(column+n).getWidth();   
  232.                             }   
  233.                             int v = ((GridBagTable)table).getGridBagModel().getRowGrid(row, column);   
  234.                             if( v >1 ){   
  235.                                 forint n=1; n
  236.                                     cellRect.height += table.getRowHeight(row+n);   
  237.                             }   
  238.                         }              
  239.                     }                                                                          
  240.                     if (aColumn != draggedColumn) {   
  241.                         paintCell(g, cellRect, row, column);   
  242.                     }                          
  243.                     cellRect.height = oldHeight;                       
  244.                     cellRect.x += columnWidth;   
  245.                 }   
  246.             }   
  247.         } else {   
  248.             for(int row = rMin; row <= rMax; row++) {   
  249.                     cellRect = table.getCellRect(row, cMin, false);   
  250.                     aColumn = cm.getColumn(cMin);   
  251.                     if (aColumn != draggedColumn) {   
  252.                         columnWidth = aColumn.getWidth();   
  253.                         cellRect.width = columnWidth - columnMargin;   
  254.                         paintCell(g, cellRect, row, cMin);   
  255.                     }   
  256.                     for(int column = cMin+1; column <= cMax; column++) {   
  257.                         aColumn = cm.getColumn(column);   
  258.                         columnWidth = aColumn.getWidth();   
  259. //                      TODO   
  260.                         cellRect.width = columnWidth - columnMargin;   
  261.                         cellRect.x -= columnWidth;   
  262.                         if (aColumn != draggedColumn) {   
  263.                             paintCell(g, cellRect, row, column);   
  264.                         }   
  265.                 }   
  266.             }   
  267.         }   
  268.   
  269.             // Paint the dragged column if we are dragging.   
  270.             if (draggedColumn != null) {   
  271.             paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());   
  272.         }   
  273.   
  274.         // Remove any renderers that may be left in the rendererPane.   
  275.         rendererPane.removeAll();   
  276.         }   
  277.        
  278.     private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {   
  279.         if (table.isEditing() && table.getEditingRow()==row &&   
  280.                                  table.getEditingColumn()==column) {   
  281.             Component component = table.getEditorComponent();   
  282.         component.setBounds(cellRect);   
  283.             component.validate();   
  284.         }   
  285.         else {   
  286.             TableCellRenderer renderer = table.getCellRenderer(row, column);   
  287.             Component component = table.prepareRenderer(renderer, row, column);   
  288.                
  289.             if( component instanceof JComponent ){   
  290.                 ((JComponent)component).setBorder(BorderFactory.createLineBorder(Color.gray));   
  291.             }   
  292.             rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,   
  293.                                         cellRect.width, cellRect.height, true);              
  294.         }   
  295.     }   
  296.        
  297.     private Rectangle getHDropLineRect(JTable.DropLocation loc) {   
  298.         if (!loc.isInsertRow()) {   
  299.             return null;   
  300.         }   
  301.   
  302.         int row = loc.getRow();   
  303.         int col = loc.getColumn();   
  304.         if (col >= table.getColumnCount()) {   
  305.             col--;   
  306.         }   
  307.   
  308.         Rectangle rect = table.getCellRect(row, col, true);   
  309.   
  310.         if (row >= table.getRowCount()) {   
  311.             row--;   
  312.             Rectangle prevRect = table.getCellRect(row, col, true);   
  313.             rect.y = prevRect.y + prevRect.height;   
  314.         }   
  315.   
  316.         if (rect.y == 0) {   
  317.             rect.y = -1;   
  318.         } else {   
  319.             rect.y -= 2;   
  320.         }   
  321.   
  322.         rect.height = 3;   
  323.   
  324.         return rect;   
  325.     }   
  326.        
  327.     private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {   
  328.         int draggedColumnIndex = viewIndexForColumn(draggedColumn);   
  329.   
  330.         Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);   
  331.     Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);   
  332.   
  333.     Rectangle vacatedColumnRect = minCell.union(maxCell);   
  334.   
  335.     // Paint a gray well in place of the moving column.   
  336.     g.setColor(table.getParent().getBackground());   
  337.     g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,   
  338.            vacatedColumnRect.width, vacatedColumnRect.height);   
  339.   
  340.     // Move to the where the cell has been dragged.   
  341.     vacatedColumnRect.x += distance;   
  342.   
  343.     // Fill the background.   
  344.     g.setColor(table.getBackground());   
  345.     g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,   
  346.            vacatedColumnRect.width, vacatedColumnRect.height);   
  347.   
  348.     // Paint the vertical grid lines if necessary.   
  349.     if (table.getShowVerticalLines()) {   
  350.         g.setColor(table.getGridColor());   
  351.         int x1 = vacatedColumnRect.x;   
  352.         int y1 = vacatedColumnRect.y;   
  353.         int x2 = x1 + vacatedColumnRect.width - 1;   
  354.         int y2 = y1 + vacatedColumnRect.height - 1;   
  355.         // Left   
  356.         g.drawLine(x1-1, y1, x1-1, y2);   
  357.         // Right   
  358.         g.drawLine(x2, y1, x2, y2);   
  359.     }   
  360.   
  361.     for(int row = rMin; row <= rMax; row++) {   
  362.         // Render the cell value   
  363.         Rectangle r = table.getCellRect(row, draggedColumnIndex, false);   
  364.         r.x += distance;   
  365.         paintCell(g, r, row, draggedColumnIndex);   
  366.   
  367.         // Paint the (lower) horizontal grid line if necessary.   
  368.         if (table.getShowHorizontalLines()) {   
  369.         g.setColor(table.getGridColor());   
  370.         Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);   
  371.         rcr.x += distance;   
  372.         int x1 = rcr.x;   
  373.         int y1 = rcr.y;   
  374.         int x2 = x1 + rcr.width - 1;   
  375.         int y2 = y1 + rcr.height - 1;   
  376.         g.drawLine(x1, y2, x2, y2);   
  377.         }   
  378.     }   
  379.     }   
  380.        
  381.     private int viewIndexForColumn(TableColumn aColumn) {   
  382.         TableColumnModel cm = table.getColumnModel();   
  383.         for (int column = 0; column < cm.getColumnCount(); column++) {   
  384.             if (cm.getColumn(column) == aColumn) {   
  385.                 return column;   
  386.             }   
  387.         }   
  388.         return -1;   
  389.     }   
  390.        
  391.     private Rectangle extendRect(Rectangle rect, boolean horizontal) {   
  392.         if (rect == null) {   
  393.             return rect;   
  394.         }   
  395.   
  396.         if (horizontal) {   
  397.             rect.x = 0;   
  398.             rect.width = table.getWidth();   
  399.         } else {   
  400.             rect.y = 0;   
  401.   
  402.             if (table.getRowCount() != 0) {   
  403.                 Rectangle lastRect = table.getCellRect(table.getRowCount() - 10true);   
  404.                 rect.height = lastRect.y + lastRect.height;   
  405.             } else {   
  406.                 rect.height = table.getHeight();   
  407.             }   
  408.         }   
  409.   
  410.         return rect;   
  411.     }   
  412.        
  413.     private Rectangle getVDropLineRect(JTable.DropLocation loc) {   
  414.         if (!loc.isInsertColumn()) {   
  415.             return null;   
  416.         }   
  417.   
  418.         boolean ltr = table.getComponentOrientation().isLeftToRight();   
  419.         int col = loc.getColumn();   
  420.         Rectangle rect = table.getCellRect(loc.getRow(), col, true);   
  421.   
  422.         if (col >= table.getColumnCount()) {   
  423.             col--;   
  424.             rect = table.getCellRect(loc.getRow(), col, true);   
  425.             if (ltr) {   
  426.                 rect.x = rect.x + rect.width;   
  427.             }   
  428.         } else if (!ltr) {   
  429.             rect.x = rect.x + rect.width;   
  430.         }   
  431.   
  432.         if (rect.x == 0) {   
  433.             rect.x = -1;   
  434.         } else {   
  435.             rect.x -= 2;   
  436.         }   
  437.            
  438.         rect.width = 3;   
  439.   
  440.         return rect;   
  441.     }   
  442.   
  443. }  // End of Class BasicTableUI  
package org.dxj.guitools.gridbagtable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Enumeration;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class GridBagTableUI extends BasicTableUI
{
    public Dimension getPreferredSize(JComponent c) {
        long width = 0;
        Enumeration enumeration = table.getColumnModel().getColumns();
        while (enumeration.hasMoreElements()) {
            TableColumn aColumn = (TableColumn)enumeration.nextElement();
            width = width + aColumn.getPreferredWidth();
        }
        return createTableSize(width);
    }
    
    private Dimension createTableSize(long width) {
    	int height = 0;
    	int rowCount = table.getRowCount();
    	if (rowCount > 0 && table.getColumnCount() > 0) {
    	    Rectangle r = table.getCellRect(rowCount-1, 0, true);
    	    height = r.y + r.height;
    	}
    	// Width is always positive. The call to abs() is a workaround for
    	// a bug in the 1.1.6 JIT on Windows.
    	long tmp = Math.abs(width);
            if (tmp > Integer.MAX_VALUE) {
                tmp = Integer.MAX_VALUE;
            }
    	return new Dimension((int)tmp, height);
        }
    
    public void paint(Graphics g, JComponent c) {
        Rectangle clip = g.getClipBounds();

        Rectangle bounds = table.getBounds();
        // account for the fact that the graphics has already been translated
        // into the table's bounds
        bounds.x = bounds.y = 0;

	if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
                // this check prevents us from painting the entire table
                // when the clip doesn't intersect our bounds at all
                !bounds.intersects(clip)) {

            paintDropLines(g);
	    return;
	}

        boolean ltr = table.getComponentOrientation().isLeftToRight();

	Point upperLeft = clip.getLocation();
        if (!ltr) {
            upperLeft.x++;
        }

	Point lowerRight = new Point(clip.x + clip.width - (ltr ? 1 : 0),
                                     clip.y + clip.height);

        int rMin = table.rowAtPoint(upperLeft);
        int rMax = table.rowAtPoint(lowerRight);
        // This should never happen (as long as our bounds intersect the clip,
        // which is why we bail above if that is the case).
        if (rMin == -1) {
	    rMin = 0;
        }
        // If the table does not have enough rows to fill the view we'll get -1.
        // (We could also get -1 if our bounds don't intersect the clip,
        // which is why we bail above if that is the case).
        // Replace this with the index of the last row.
        if (rMax == -1) {
	    rMax = table.getRowCount()-1;
        }

        int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight); 
        int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);        
        // This should never happen.
        if (cMin == -1) {
	    cMin = 0;
        }
	// If the table does not have enough columns to fill the view we'll get -1.
        // Replace this with the index of the last column.
        if (cMax == -1) {
	    cMax = table.getColumnCount()-1;
        }

        // Paint the grid.
        //paintGrid(g, rMin, rMax, cMin, cMax);

        // Paint the cells.
	paintCells(g, rMin, rMax, cMin, cMax);

        paintDropLines(g);
    }
    
    private void paintDropLines(Graphics g) {
        JTable.DropLocation loc = table.getDropLocation();
        if (loc == null) {
            return;
        }

        Color color = UIManager.getColor("Table.dropLineColor");
        Color shortColor = UIManager.getColor("Table.dropLineShortColor");
        if (color == null && shortColor == null) {
            return;
        }

        Rectangle rect;

        rect = getHDropLineRect(loc);
        if (rect != null) {
            int x = rect.x;
            int w = rect.width;
            if (color != null) {
                extendRect(rect, true);
                g.setColor(color);
                g.fillRect(rect.x, rect.y, rect.width, rect.height);
            }
            if (!loc.isInsertColumn() && shortColor != null) {
                g.setColor(shortColor);
                g.fillRect(x, rect.y, w, rect.height);
            }
        }

        rect = getVDropLineRect(loc);
        if (rect != null) {
            int y = rect.y;
            int h = rect.height;
            if (color != null) {
                extendRect(rect, false);
                g.setColor(color);
                g.fillRect(rect.x, rect.y, rect.width, rect.height);
            }
            if (!loc.isInsertRow() && shortColor != null) {
                g.setColor(shortColor);
                g.fillRect(rect.x, y, rect.width, h);
            }
        }
    }
    
    /*
     * Paints the grid lines within aRect, using the grid
     * color set with setGridColor. Paints vertical lines
     * if getShowVerticalLines() returns true and paints
     * horizontal lines if getShowHorizontalLines()
     * returns true.
     */
    private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {
        g.setColor(table.getGridColor());

        Rectangle minCell = table.getCellRect(rMin, cMin, true);
        Rectangle maxCell = table.getCellRect(rMax, cMax, true);
        Rectangle damagedArea = minCell.union( maxCell );

		if (table.getShowHorizontalLines()) {
			int tableWidth = damagedArea.x + damagedArea.width;
			int y = damagedArea.y;
			for (int row = rMin; row <= rMax; row++) {
				y += table.getRowHeight(row);
				g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);
			}
		}
		if (table.getShowVerticalLines()) {
			TableColumnModel cm = table.getColumnModel();
			int tableHeight = damagedArea.y + damagedArea.height;
			int x;
			if (table.getComponentOrientation().isLeftToRight()) {
				x = damagedArea.x;
				for (int column = cMin; column <= cMax; column++) {
					int w = cm.getColumn(column).getWidth();
					x += w;
					g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
				}
			} else {
				x = damagedArea.x;
				for (int column = cMax; column >= cMin; column--) {
					int w = cm.getColumn(column).getWidth();
					x += w;
					g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
				}
			}
		}
    }
    
    private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {
    	JTableHeader header = table.getTableHeader();
    	TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();

    	TableColumnModel cm = table.getColumnModel();
    	int columnMargin = cm.getColumnMargin();
            Rectangle cellRect;
    	TableColumn aColumn;
    	int columnWidth;
    	if (table.getComponentOrientation().isLeftToRight()) {
    	    for(int row = rMin; row <= rMax; row++) {
    	    	if( table instanceof GridBagTable )
    	    		cellRect = ((GridBagTable)table).getGridCellRect(row, cMin, false);
    	    	else
    	    		cellRect = table.getCellRect(row, cMin, false);
                for(int column = cMin; column <= cMax; column++) {
                    aColumn = cm.getColumn(column);
                    columnWidth = aColumn.getWidth();                                 
                    //TODO
                    cellRect.width = columnWidth - columnMargin;
                    int oldHeight = cellRect.height;
                    if( table instanceof GridBagTable ){
                    	if(((GridBagTable)table).getGridBagModel().getCellState( row, column) == GridBagModel.COVERED ) {
                        	cellRect.width = 0;
                        	cellRect.height = 0;
                        }
                    	else{
                    		int h = ((GridBagTable)table).getGridBagModel().getColumnGrid(row, column);
                        	if( h >1 ){
                        		for( int n=1; n1 ){
                        		for( int n=1; n= table.getColumnCount()) {
            col--;
        }

        Rectangle rect = table.getCellRect(row, col, true);

        if (row >= table.getRowCount()) {
            row--;
            Rectangle prevRect = table.getCellRect(row, col, true);
            rect.y = prevRect.y + prevRect.height;
        }

        if (rect.y == 0) {
            rect.y = -1;
        } else {
            rect.y -= 2;
        }

        rect.height = 3;

        return rect;
    }
    
    private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
        int draggedColumnIndex = viewIndexForColumn(draggedColumn);

        Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
	Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);

	Rectangle vacatedColumnRect = minCell.union(maxCell);

	// Paint a gray well in place of the moving column.
	g.setColor(table.getParent().getBackground());
	g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
		   vacatedColumnRect.width, vacatedColumnRect.height);

	// Move to the where the cell has been dragged.
	vacatedColumnRect.x += distance;

	// Fill the background.
	g.setColor(table.getBackground());
	g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
		   vacatedColumnRect.width, vacatedColumnRect.height);

	// Paint the vertical grid lines if necessary.
	if (table.getShowVerticalLines()) {
	    g.setColor(table.getGridColor());
	    int x1 = vacatedColumnRect.x;
	    int y1 = vacatedColumnRect.y;
	    int x2 = x1 + vacatedColumnRect.width - 1;
	    int y2 = y1 + vacatedColumnRect.height - 1;
	    // Left
	    g.drawLine(x1-1, y1, x1-1, y2);
	    // Right
	    g.drawLine(x2, y1, x2, y2);
	}

	for(int row = rMin; row <= rMax; row++) {
	    // Render the cell value
	    Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
	    r.x += distance;
	    paintCell(g, r, row, draggedColumnIndex);

	    // Paint the (lower) horizontal grid line if necessary.
	    if (table.getShowHorizontalLines()) {
		g.setColor(table.getGridColor());
		Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
		rcr.x += distance;
		int x1 = rcr.x;
		int y1 = rcr.y;
		int x2 = x1 + rcr.width - 1;
		int y2 = y1 + rcr.height - 1;
		g.drawLine(x1, y2, x2, y2);
	    }
	}
    }
    
    private int viewIndexForColumn(TableColumn aColumn) {
        TableColumnModel cm = table.getColumnModel();
        for (int column = 0; column < cm.getColumnCount(); column++) {
            if (cm.getColumn(column) == aColumn) {
                return column;
            }
        }
        return -1;
    }
    
    private Rectangle extendRect(Rectangle rect, boolean horizontal) {
        if (rect == null) {
            return rect;
        }

        if (horizontal) {
            rect.x = 0;
            rect.width = table.getWidth();
        } else {
            rect.y = 0;

            if (table.getRowCount() != 0) {
                Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
                rect.height = lastRect.y + lastRect.height;
            } else {
                rect.height = table.getHeight();
            }
        }

        return rect;
    }
    
    private Rectangle getVDropLineRect(JTable.DropLocation loc) {
        if (!loc.isInsertColumn()) {
            return null;
        }

        boolean ltr = table.getComponentOrientation().isLeftToRight();
        int col = loc.getColumn();
        Rectangle rect = table.getCellRect(loc.getRow(), col, true);

        if (col >= table.getColumnCount()) {
            col--;
            rect = table.getCellRect(loc.getRow(), col, true);
            if (ltr) {
                rect.x = rect.x + rect.width;
            }
        } else if (!ltr) {
            rect.x = rect.x + rect.width;
        }

        if (rect.x == 0) {
            rect.x = -1;
        } else {
            rect.x -= 2;
        }
        
        rect.width = 3;

        return rect;
    }

}  // End of Class BasicTableUI

  测试代码:

Java代码 复制代码  收藏代码
  1. import java.awt.BorderLayout;   
  2. import java.awt.event.ActionEvent;   
  3. import java.awt.event.ActionListener;   
  4.   
  5. import javax.swing.JButton;   
  6. import javax.swing.JFrame;   
  7. import javax.swing.JScrollPane;   
  8. import javax.swing.table.DefaultTableModel;   
  9.   
  10. import com.jrf.jgrid.guitools.gridbagtable.GridBagTable;   
  11.   
  12.   
  13. public class Test implements ActionListener{   
  14.        
  15.     GridBagTable table;   
  16.     public Test()   
  17.     {   
  18.         JFrame d = new JFrame();   
  19.         DefaultTableModel model = new DefaultTableModel(5,5);   
  20.            
  21.         table = new GridBagTable(model);   
  22.         table.setRowHeight(20);   
  23.            
  24.         JScrollPane pane = new JScrollPane(table);   
  25.         d.getContentPane().add(pane, BorderLayout.CENTER);   
  26.         JButton btn = new JButton("合并/拆分");   
  27.         d.getContentPane().add(btn, BorderLayout.NORTH);   
  28.         btn.addActionListener(this);   
  29.         d.setBounds(00400400);   
  30.         d.setVisible(true);   
  31.     }   
  32.        
  33.     public static void main(String[] fsd){   
  34.         new Test();   
  35.     }   
  36.        
  37.     public void actionPerformed(ActionEvent e) {   
  38.         table.mergeCells(table.getSelectedRows(), table.getSelectedColumns());   
  39.     }   
  40. }  年前在网上参加了一个JavaSwing的招聘上机考试。招聘方要求开发一个类似EXCEL支持单元格合并的JTable。差不多用了5天的时间提交代码,最后被告知测试通过,我提出是否可做兼职,对方回复需要到上海做全职开发,最后也就放弃了。最近公司的一个项目中需要用到以前的代码,偶又重构了一次,设计思想来源于ListSelectionModel。

     

    Java Swing写的支持合并单元格的JTable_第2张图片

    GridBagModel:抽象模型接口。该接口用于描述表格中单元格的合并状态。
    DefaultGridBagTableModel:GridBagModel的默认实现。
    GridBagTable:继承自JTable的控制器。通过该类中的方法控制表格单元的合并和拆分。
    GridBagTableUI:GridBagTable对应的UI。

    TODO:(已合并)行、列的插入,删除操作对应的GridBagModel的修改,不过已留接口。

    Java代码 复制代码  收藏代码
    1. package org.dxj.guitools.gridbagtable;   
    2. import java.awt.Component;   
    3. import java.awt.Point;   
    4. import java.awt.Rectangle;   
    5. import java.util.Enumeration;   
    6. import java.util.EventObject;   
    7.   
    8. import javax.swing.DefaultCellEditor;   
    9. import javax.swing.JTable;   
    10. import javax.swing.SwingUtilities;   
    11. import javax.swing.event.TableModelEvent;   
    12. import javax.swing.table.AbstractTableModel;   
    13. import javax.swing.table.TableColumn;   
    14. import javax.swing.table.TableColumnModel;   
    15.   
    16. /**  
    17.  * @author [email protected]  
    18.  */  
    19. public class GridBagTable extends JTable{   
    20.   
    21.     GridBagModel gridBagModel;   
    22.        
    23.     public GridBagModel getGridBagModel() {   
    24.         return gridBagModel;   
    25.     }   
    26.        
    27.     public void setGridBagModel(GridBagModel gridBagModel){   
    28.         if( gridBagModel != null && gridBagModel != this.gridBagModel )   
    29.             this.gridBagModel = gridBagModel;   
    30.     }   
    31.   
    32.     public GridBagTable(AbstractTableModel dm){   
    33.         super(dm);         
    34.         getTableHeader().setReorderingAllowed(false);   
    35.         gridBagModel = new DefaultGridBagTableModel(dm);           
    36.         getColumnModel().setColumnSelectionAllowed(true);   
    37.     }   
    38.        
    39.      private void updateSubComponentUI(Object componentShell) {   
    40.         if (componentShell == null) {   
    41.             return;   
    42.         }   
    43.         Component component = null;   
    44.         if (componentShell instanceof Component) {   
    45.             component = (Component)componentShell;   
    46.         }   
    47.         if (componentShell instanceof DefaultCellEditor) {   
    48.             component = ((DefaultCellEditor)componentShell).getComponent();   
    49.         }   
    50.   
    51.         if (component != null) {   
    52.             SwingUtilities.updateComponentTreeUI(component);   
    53.         }   
    54.     }   
    55.        
    56.     public void updateUI() {       
    57.         // Update the UIs of the cell renderers, cell editors and header renderers.   
    58.         TableColumnModel cm = getColumnModel();   
    59.         for(int column = 0; column < cm.getColumnCount(); column++) {   
    60.             TableColumn aColumn = cm.getColumn(column);   
    61.         updateSubComponentUI(aColumn.getCellRenderer());   
    62.             updateSubComponentUI(aColumn.getCellEditor());   
    63.         updateSubComponentUI(aColumn.getHeaderRenderer());   
    64.         }   
    65.   
    66.         // Update the UIs of all the default renderers.   
    67.         Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();   
    68.         while (defaultRenderers.hasMoreElements()) {   
    69.             updateSubComponentUI(defaultRenderers.nextElement());   
    70.         }   
    71.   
    72.         // Update the UIs of all the default editors.   
    73.         Enumeration defaultEditors = defaultEditorsByColumnClass.elements();   
    74.         while (defaultEditors.hasMoreElements()) {   
    75.             updateSubComponentUI(defaultEditors.nextElement());   
    76.         }   
    77.   
    78.         // Update the UI of the table header   
    79.         if (tableHeader != null && tableHeader.getParent() == null) {   
    80.             tableHeader.updateUI();   
    81.         }   
    82.         setUI(new GridBagTableUI());   
    83.     }   
    84.        
    85.     public Rectangle getGridCellRect(int row, int column, boolean includeSpacing){   
    86.         return super.getCellRect(row, column, includeSpacing);   
    87.     }   
    88.        
    89.     public Rectangle getCellRect(int row, int column, boolean includeSpacing) {        
    90.         Rectangle cellRect = super.getCellRect(row, column, includeSpacing);   
    91.         int cols = gridBagModel.getColumnGrid(row, column);   
    92.         TableColumnModel cm = getColumnModel();   
    93.         forint n=1; n
    94.             cellRect.width += cm.getColumn(column+n).getWidth();   
    95.         int rows = gridBagModel.getRowGrid(row, column);   
    96.         forint n=1; n
    97.             cellRect.height += getRowHeight(row+n);   
    98.         return cellRect;            
    99.     }   
    100.        
    101.     public void tableChanged(TableModelEvent e){   
    102.         super.tableChanged(e);   
    103.         //TODO   
    104.     }   
    105.        
    106.     public boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn){   
    107.         if( gridBagModel.mergeCells(startRow, endRow, startColumn, endColumn)){   
    108.             repaint();   
    109.             return true;   
    110.         }      
    111.         return false;   
    112.     }   
    113.         
    114.     public boolean mergeCells(int[] rows, int[] columns){   
    115.         if( gridBagModel.mergeCells(rows, columns)){   
    116.             repaint();   
    117.             return true;   
    118.         }      
    119.         return false;   
    120.     }   
    121.        
    122.     public boolean spliteCellAt(int row, int column){   
    123.         if( gridBagModel.spliteCellAt(row, column)){   
    124.             repaint();   
    125.             return true;   
    126.         }   
    127.         return false;   
    128.     }   
    129.        
    130.     public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {   
    131.         if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )   
    132.             super.changeSelection(rowIndex, columnIndex, toggle, extend);   
    133.         Point p;   
    134.         forint row = rowIndex; row >= 0; row-- ){   
    135.             forint col = columnIndex; col >= 0; col-- ){   
    136.                 p = gridBagModel.getGrid(row, col);   
    137.                 //p = ((Point)((Vector)rowVector.get(row)).get(col));   
    138.                 if( col + p.x > columnIndex && row + p.y > rowIndex){   
    139.                     rowIndex = row;   
    140.                     columnIndex = col;   
    141.                     break;   
    142.                 }   
    143.             }   
    144.         }      
    145.         super.changeSelection(rowIndex, columnIndex, toggle, extend);   
    146.         repaint();   
    147.     }   
    148.        
    149.     public boolean editCellAt(int rowIndex, int columnIndex, EventObject e){   
    150.         if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )   
    151.             return super.editCellAt(rowIndex, columnIndex, e);      
    152.         Point p;   
    153.         forint row = rowIndex; row >= 0; row-- ){   
    154.             forint col = columnIndex; col >= 0; col-- ){   
    155.                 p = gridBagModel.getGrid(row, col);   
    156.                 if( col + p.x > columnIndex && row + p.y > rowIndex){   
    157.                     rowIndex = row;   
    158.                     columnIndex = col;   
    159.                     break;   
    160.                 }   
    161.             }   
    162.         }          
    163.         return super.editCellAt(rowIndex, columnIndex, e);           
    164.     }   
    165. }  
    package org.dxj.guitools.gridbagtable;
    import java.awt.Component;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.util.Enumeration;
    import java.util.EventObject;
    
    import javax.swing.DefaultCellEditor;
    import javax.swing.JTable;
    import javax.swing.SwingUtilities;
    import javax.swing.event.TableModelEvent;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.TableColumn;
    import javax.swing.table.TableColumnModel;
    
    /**
     * @author [email protected]
     */
    public class GridBagTable extends JTable{
    
    	GridBagModel gridBagModel;
    	
    	public GridBagModel getGridBagModel() {
    		return gridBagModel;
    	}
    	
    	public void setGridBagModel(GridBagModel gridBagModel){
    		if( gridBagModel != null && gridBagModel != this.gridBagModel )
    			this.gridBagModel = gridBagModel;
    	}
    
    	public GridBagTable(AbstractTableModel dm){
    		super(dm);		
    		getTableHeader().setReorderingAllowed(false);
    		gridBagModel = new DefaultGridBagTableModel(dm);		
    		getColumnModel().setColumnSelectionAllowed(true);
    	}
    	
    	 private void updateSubComponentUI(Object componentShell) {
            if (componentShell == null) {
                return;
            }
            Component component = null;
            if (componentShell instanceof Component) {
                component = (Component)componentShell;
            }
            if (componentShell instanceof DefaultCellEditor) {
                component = ((DefaultCellEditor)componentShell).getComponent();
            }
    
            if (component != null) {
                SwingUtilities.updateComponentTreeUI(component);
            }
        }
    	
    	public void updateUI() {	
            // Update the UIs of the cell renderers, cell editors and header renderers.
            TableColumnModel cm = getColumnModel();
            for(int column = 0; column < cm.getColumnCount(); column++) {
                TableColumn aColumn = cm.getColumn(column);
    	    updateSubComponentUI(aColumn.getCellRenderer());
                updateSubComponentUI(aColumn.getCellEditor());
    	    updateSubComponentUI(aColumn.getHeaderRenderer());
            }
    
            // Update the UIs of all the default renderers.
            Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
            while (defaultRenderers.hasMoreElements()) {
                updateSubComponentUI(defaultRenderers.nextElement());
            }
    
            // Update the UIs of all the default editors.
            Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
            while (defaultEditors.hasMoreElements()) {
                updateSubComponentUI(defaultEditors.nextElement());
            }
    
            // Update the UI of the table header
            if (tableHeader != null && tableHeader.getParent() == null) {
                tableHeader.updateUI();
            }
            setUI(new GridBagTableUI());
        }
    	
    	public Rectangle getGridCellRect(int row, int column, boolean includeSpacing){
    		return super.getCellRect(row, column, includeSpacing);
    	}
    	
    	public Rectangle getCellRect(int row, int column, boolean includeSpacing) {		
    		Rectangle cellRect = super.getCellRect(row, column, includeSpacing);
    		int cols = gridBagModel.getColumnGrid(row, column);
    		TableColumnModel cm = getColumnModel();
    		for( int n=1; n= 0; row-- ){
    			for( int col = columnIndex; col >= 0; col-- ){
    				p = gridBagModel.getGrid(row, col);
    				//p = ((Point)((Vector)rowVector.get(row)).get(col));
    				if( col + p.x > columnIndex && row + p.y > rowIndex){
    					rowIndex = row;
    					columnIndex = col;
    					break;
    				}
        		}
    		}  	
        	super.changeSelection(rowIndex, columnIndex, toggle, extend);
        	repaint();
        }
        
        public boolean editCellAt(int rowIndex, int columnIndex, EventObject e){
        	if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )
        		return super.editCellAt(rowIndex, columnIndex, e);   
    		Point p;
    		for( int row = rowIndex; row >= 0; row-- ){
    			for( int col = columnIndex; col >= 0; col-- ){
    				p = gridBagModel.getGrid(row, col);
    				if( col + p.x > columnIndex && row + p.y > rowIndex){
    					rowIndex = row;
    					columnIndex = col;
    					break;
    				}
        		}
    		}   	
        	return super.editCellAt(rowIndex, columnIndex, e);        
        }
    }
    
     
    Java代码 复制代码  收藏代码
    1. package org.dxj.guitools.gridbagtable;   
    2.   
    3. import java.awt.Point;   
    4.   
    5. public interface GridBagModel {   
    6.     //格子处于正常状态   
    7.     int DEFAULT = 0;   
    8.     //格子合并了其他的格子   
    9.     int MERGE = 1;   
    10.     //格子被其他格子合并   
    11.     int COVERED = -1;   
    12.        
    13.     /**  
    14.      * @param row 行  
    15.      * @param column 列  
    16.      * @return 该单元格在行、列的跨度  
    17.      */  
    18.     Point getGrid(int row, int column);   
    19.        
    20.     /**  
    21.      * 在Y轴方向的跨度  
    22.      * @param row  
    23.      * @param column  
    24.      * @return  
    25.      */  
    26.     int getRowGrid(int row, int column);   
    27.        
    28.     /**  
    29.      * 在X轴方向的跨度  
    30.      * @param row  
    31.      * @param column  
    32.      * @return  
    33.      */  
    34.     int getColumnGrid(int row, int column);   
    35.   
    36.     /**  
    37.      * @param rows 行集合  
    38.      * @param columns 列集合  
    39.      * @return 单元格集合是否可以合并在一起  
    40.      */  
    41.     boolean canMergeCells(int[] rows, int[] columns);   
    42.        
    43.     /**  
    44.      * 判断该单元格状态  
    45.      * @param row  
    46.      * @param column  
    47.      * @return MERGE|DEFAULT|COVERED  
    48.      */  
    49.     int getCellState(int row, int column);   
    50.        
    51.     /**  
    52.      * 将单元格集合合并  
    53.      * @param startRow 开始行  
    54.      * @param endRow 结束行  
    55.      * @param startColumn 开始列  
    56.      * @param endColumn 结束列  
    57.      * @return 是否合并成功  
    58.      */  
    59.     boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn);   
    60.        
    61.     /**  
    62.      * 将单元格集合合并  
    63.      * @param rows 行集合  
    64.      * @param columns 列集合  
    65.      * @return 是否合并成功  
    66.      */  
    67.     boolean mergeCells(int[] rows, int[] columns);   
    68.        
    69.     /**  
    70.      * 拆分单元格  
    71.      * @param row 行  
    72.      * @param column 列  
    73.      * @return 是否拆分成功  
    74.      */  
    75.     boolean spliteCellAt(int row, int column);   
    76.        
    77.     /**  
    78.      * 清除 所有合并  
    79.      */  
    80.     void clearMergence();   
    81. }  
    package org.dxj.guitools.gridbagtable;
    
    import java.awt.Point;
    
    public interface GridBagModel {
    	//格子处于正常状态
    	int DEFAULT = 0;
    	//格子合并了其他的格子
    	int MERGE = 1;
    	//格子被其他格子合并
    	int COVERED = -1;
    	
    	/**
    	 * @param row 行
    	 * @param column 列
    	 * @return 该单元格在行、列的跨度
    	 */
    	Point getGrid(int row, int column);
    	
    	/**
    	 * 在Y轴方向的跨度
    	 * @param row
    	 * @param column
    	 * @return
    	 */
    	int getRowGrid(int row, int column);
    	
    	/**
    	 * 在X轴方向的跨度
    	 * @param row
    	 * @param column
    	 * @return
    	 */
    	int getColumnGrid(int row, int column);
    
    	/**
    	 * @param rows 行集合
    	 * @param columns 列集合
    	 * @return 单元格集合是否可以合并在一起
    	 */
    	boolean canMergeCells(int[] rows, int[] columns);
    	
    	/**
    	 * 判断该单元格状态
    	 * @param row
    	 * @param column
    	 * @return MERGE|DEFAULT|COVERED
    	 */
    	int getCellState(int row, int column);
    	
    	/**
    	 * 将单元格集合合并
    	 * @param startRow 开始行
    	 * @param endRow 结束行
    	 * @param startColumn 开始列
    	 * @param endColumn 结束列
    	 * @return 是否合并成功
    	 */
    	boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn);
    	
    	/**
    	 * 将单元格集合合并
    	 * @param rows 行集合
    	 * @param columns 列集合
    	 * @return 是否合并成功
    	 */
    	boolean mergeCells(int[] rows, int[] columns);
    	
    	/**
    	 * 拆分单元格
    	 * @param row 行
    	 * @param column 列
    	 * @return 是否拆分成功
    	 */
    	boolean spliteCellAt(int row, int column);
    	
    	/**
    	 * 清除 所有合并
    	 */
    	void clearMergence();
    }
    
     
    Java代码 复制代码  收藏代码
    1. package org.dxj.guitools.gridbagtable;   
    2.   
    3. import java.awt.Point;   
    4. import java.util.Arrays;   
    5. import java.util.List;   
    6. import java.util.Vector;   
    7.   
    8. import javax.swing.event.TableModelEvent;   
    9. import javax.swing.event.TableModelListener;   
    10. import javax.swing.table.AbstractTableModel;   
    11.   
    12. public class DefaultGridBagTableModel implements GridBagModel, TableModelListener{   
    13.     protected AbstractTableModel model;   
    14.     protected List> gridInfo;   
    15.        
    16.     DefaultGridBagTableModel(AbstractTableModel model){   
    17.         gridInfo = new Vector>();   
    18.         setTableModel(model);   
    19.     }   
    20.        
    21.     public void setTableModel(AbstractTableModel model){   
    22.         if( model != null && model != this.model ){   
    23.             ifthis.model != null )   
    24.                 this.model.removeTableModelListener(this);   
    25.             //防止多次添加监听器   
    26.             model.removeTableModelListener(this);   
    27.             model.addTableModelListener(this);   
    28.             this.model = model;   
    29.             clearMergence();   
    30.         }   
    31.     }   
    32.        
    33.     public void clearMergence(){   
    34.         if( gridInfo == null  )   
    35.             gridInfo = new Vector>();   
    36.         else  
    37.             gridInfo.clear();   
    38.            
    39.         if( model == null )   
    40.             return;   
    41.            
    42.         //初始化,每个格子占的格子数为(1,1);   
    43.         for(int row=model.getRowCount(); --row>=0;){   
    44.             List infos = new Vector();   
    45.             gridInfo.add(infos);   
    46.             for(int col=model.getColumnCount(); --col>=0;){   
    47.                 infos.add(getDefaultPoint());   
    48.             }   
    49.         }   
    50.     }   
    51.        
    52.     public Point getDefaultPoint(){   
    53.         return new Point(1,1);   
    54.     }   
    55.        
    56.     @Override  
    57.     public boolean canMergeCells(int[] rows, int[] columns) {   
    58.         if( rows == null || columns == null ) return false;   
    59.         Arrays.sort(rows);   
    60.         for(int index=0; index1; index++){   
    61.             if( rows[index+1] - rows[index] > 1 )   
    62.                 return false;   
    63.         }   
    64.         Arrays.sort(columns);   
    65.         for(int index=0; index1; index++){   
    66.             if( columns[index+1] - columns[index] > 1 )   
    67.                 return false;   
    68.         }   
    69.         return true;   
    70.     }   
    71.        
    72.     @Override  
    73.     public int getCellState(int row, int column) {   
    74.         Point grid = getGrid(row, column);   
    75.         if( grid == null ) return DEFAULT;   
    76.         if( grid.x>1 || grid.y>1 )   
    77.             return MERGE;   
    78.         if( grid.x<=0 || grid.y<=0 )   
    79.             return COVERED;   
    80.         return DEFAULT;   
    81.     }   
    82.   
    83.     @Override  
    84.     public int getColumnGrid(int row, int column) {   
    85.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
    86.             List gridRow = gridInfo.get(row);   
    87.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
    88.                 Point point = gridRow.get(column);   
    89.                 if( point != null )   
    90.                     return point.x;   
    91.             }      
    92.         }   
    93.         return 1;   
    94.     }   
    95.   
    96.     @Override  
    97.     public Point getGrid(int row, int column) {   
    98.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
    99.             List gridRow = gridInfo.get(row);   
    100.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
    101.                 return gridRow.get(column);   
    102.             }      
    103.         }   
    104.         return getDefaultPoint();   
    105.     }   
    106.   
    107.     @Override  
    108.     public int getRowGrid(int row, int column) {   
    109.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
    110.             List gridRow = gridInfo.get(row);   
    111.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
    112.                 Point point = gridRow.get(column);   
    113.                 if( point != null )   
    114.                     return point.y;   
    115.             }      
    116.         }   
    117.         return 1;   
    118.     }   
    119.   
    120.     protected boolean setGrid(int row, int column, Point grid) {   
    121.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
    122.             List gridRow = gridInfo.get(row);   
    123.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
    124.                 Point point = gridRow.get(column);   
    125.                 if( point != null ){   
    126.                     point.setLocation(grid);   
    127.                 }   
    128.                 else{   
    129.                     gridRow.set(column, grid.getLocation());   
    130.                 }   
    131.                 return true;   
    132.             }      
    133.         }   
    134.         return false;   
    135.     }   
    136.   
    137.     @Override  
    138.     public boolean spliteCellAt(int row, int column) {   
    139.         if( gridInfo != null && row >=0 && row < gridInfo.size() ){   
    140.             List gridRow = gridInfo.get(row);   
    141.             if( gridRow != null && column >=0 && column < gridRow.size() ){   
    142.                 Point point = gridRow.get(column);   
    143.                 if( point != null ){   
    144.                     point = point.getLocation();   
    145.                     for(int a=0; a
    146.                         for(int b=0; b
    147.                             setGrid(row+a, column+b, getDefaultPoint());   
    148.                         }   
    149.                     }   
    150.                 }   
    151.                 else{   
    152.                     gridRow.set(column, getDefaultPoint());   
    153.                 }   
    154.                 return true;   
    155.             }      
    156.         }   
    157.         return false;   
    158.     }   
    159.        
    160.     @Override  
    161.     /**  
    162.      * table中发生行的添加和删除的时候需要修改该模型  
    163.      */  
    164.     public void tableChanged(TableModelEvent e) {   
    165.         //TODO   
    166.     }   
    167.        
    168.     @Override  
    169.     public boolean mergeCells(int[] rows, int[] columns) {   
    170.         if( !canMergeCells(rows, columns) )   
    171.             return false;   
    172.         Arrays.sort(rows);   
    173.         Arrays.sort(columns);   
    174.         return mergeCells(rows[0],rows[rows.length-1],columns[0],columns[columns.length-1]);   
    175.     }   
    176.   
    177.     @Override  
    178.     public boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn) {   
    179.         setGrid(startRow, startColumn, new Point(endColumn-startColumn+1, endRow-startRow+1));    
    180.         for(int row=startRow; row<=endRow; row++){   
    181.             for(int col=startColumn; col<=endColumn; col++){   
    182.                 if(row==startRow&&col==startColumn)   
    183.                     continue;   
    184.                 else  
    185.                     setGrid(row, col, new Point(COVERED,COVERED));    
    186.             }   
    187.         }   
    188.         return true;   
    189.     }   
    190.        
    191.     public String toString(){   
    192.         if( gridInfo == null )   
    193.             return "";   
    194.         StringBuffer sb = new StringBuffer();   
    195.         for(List rowInfo : gridInfo ){   
    196.             for(Point grid : rowInfo){   
    197.                 sb.append("["+grid.x+","+grid.y+"], ");   
    198.             }   
    199.             sb.append("\n");   
    200.         }   
    201.         return sb.toString();   
    202.     }   
    203. }  
    package org.dxj.guitools.gridbagtable;
    
    import java.awt.Point;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Vector;
    
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;
    import javax.swing.table.AbstractTableModel;
    
    public class DefaultGridBagTableModel implements GridBagModel, TableModelListener{
    	protected AbstractTableModel model;
    	protected List> gridInfo;
    	
    	DefaultGridBagTableModel(AbstractTableModel model){
    		gridInfo = new Vector>();
    		setTableModel(model);
    	}
    	
    	public void setTableModel(AbstractTableModel model){
    		if( model != null && model != this.model ){
    			if( this.model != null )
    				this.model.removeTableModelListener(this);
    			//防止多次添加监听器
    			model.removeTableModelListener(this);
    			model.addTableModelListener(this);
    			this.model = model;
    			clearMergence();
    		}
    	}
    	
    	public void clearMergence(){
    		if( gridInfo == null  )
    			gridInfo = new Vector>();
    		else
    			gridInfo.clear();
    		
    		if( model == null )
    			return;
    		
    		//初始化,每个格子占的格子数为(1,1);
    		for(int row=model.getRowCount(); --row>=0;){
    			List infos = new Vector();
    			gridInfo.add(infos);
    			for(int col=model.getColumnCount(); --col>=0;){
    				infos.add(getDefaultPoint());
    			}
    		}
    	}
    	
    	public Point getDefaultPoint(){
    		return new Point(1,1);
    	}
    	
    	@Override
    	public boolean canMergeCells(int[] rows, int[] columns) {
    		if( rows == null || columns == null ) return false;
    		Arrays.sort(rows);
    		for(int index=0; index 1 )
    				return false;
    		}
    		Arrays.sort(columns);
    		for(int index=0; index 1 )
    				return false;
    		}
    		return true;
    	}
    	
    	@Override
    	public int getCellState(int row, int column) {
    		Point grid = getGrid(row, column);
    		if( grid == null ) return DEFAULT;
    		if( grid.x>1 || grid.y>1 )
    			return MERGE;
    		if( grid.x<=0 || grid.y<=0 )
    			return COVERED;
    		return DEFAULT;
    	}
    
    	@Override
    	public int getColumnGrid(int row, int column) {
    		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
    			List gridRow = gridInfo.get(row);
    			if( gridRow != null && column >=0 && column < gridRow.size() ){
    				Point point = gridRow.get(column);
    				if( point != null )
    					return point.x;
    			}	
    		}
    		return 1;
    	}
    
    	@Override
    	public Point getGrid(int row, int column) {
    		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
    			List gridRow = gridInfo.get(row);
    			if( gridRow != null && column >=0 && column < gridRow.size() ){
    				return gridRow.get(column);
    			}	
    		}
    		return getDefaultPoint();
    	}
    
    	@Override
    	public int getRowGrid(int row, int column) {
    		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
    			List gridRow = gridInfo.get(row);
    			if( gridRow != null && column >=0 && column < gridRow.size() ){
    				Point point = gridRow.get(column);
    				if( point != null )
    					return point.y;
    			}	
    		}
    		return 1;
    	}
    
    	protected boolean setGrid(int row, int column, Point grid) {
    		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
    			List gridRow = gridInfo.get(row);
    			if( gridRow != null && column >=0 && column < gridRow.size() ){
    				Point point = gridRow.get(column);
    				if( point != null ){
    					point.setLocation(grid);
    				}
    				else{
    					gridRow.set(column, grid.getLocation());
    				}
    				return true;
    			}	
    		}
    		return false;
    	}
    
    	@Override
    	public boolean spliteCellAt(int row, int column) {
    		if( gridInfo != null && row >=0 && row < gridInfo.size() ){
    			List gridRow = gridInfo.get(row);
    			if( gridRow != null && column >=0 && column < gridRow.size() ){
    				Point point = gridRow.get(column);
    				if( point != null ){
    					point = point.getLocation();
    					for(int a=0; a rowInfo : gridInfo ){
    			for(Point grid : rowInfo){
    				sb.append("["+grid.x+","+grid.y+"], ");
    			}
    			sb.append("\n");
    		}
    		return sb.toString();
    	}
    }
    
     
    Java代码 复制代码  收藏代码
    1. package org.dxj.guitools.gridbagtable;   
    2.   
    3. import java.awt.Color;   
    4. import java.awt.Component;   
    5. import java.awt.Dimension;   
    6. import java.awt.Graphics;   
    7. import java.awt.Point;   
    8. import java.awt.Rectangle;   
    9. import java.util.Enumeration;   
    10.   
    11. import javax.swing.BorderFactory;   
    12. import javax.swing.JComponent;   
    13. import javax.swing.JTable;   
    14. import javax.swing.UIManager;   
    15. import javax.swing.plaf.basic.BasicTableUI;   
    16. import javax.swing.table.JTableHeader;   
    17. import javax.swing.table.TableCellRenderer;   
    18. import javax.swing.table.TableColumn;   
    19. import javax.swing.table.TableColumnModel;   
    20.   
    21. public class GridBagTableUI extends BasicTableUI   
    22. {   
    23.     public Dimension getPreferredSize(JComponent c) {   
    24.         long width = 0;   
    25.         Enumeration enumeration = table.getColumnModel().getColumns();   
    26.         while (enumeration.hasMoreElements()) {   
    27.             TableColumn aColumn = (TableColumn)enumeration.nextElement();   
    28.             width = width + aColumn.getPreferredWidth();   
    29.         }   
    30.         return createTableSize(width);   
    31.     }   
    32.        
    33.     private Dimension createTableSize(long width) {   
    34.         int height = 0;   
    35.         int rowCount = table.getRowCount();   
    36.         if (rowCount > 0 && table.getColumnCount() > 0) {   
    37.             Rectangle r = table.getCellRect(rowCount-10true);   
    38.             height = r.y + r.height;   
    39.         }   
    40.         // Width is always positive. The call to abs() is a workaround for   
    41.         // a bug in the 1.1.6 JIT on Windows.   
    42.         long tmp = Math.abs(width);   
    43.             if (tmp > Integer.MAX_VALUE) {   
    44.                 tmp = Integer.MAX_VALUE;   
    45.             }   
    46.         return new Dimension((int)tmp, height);   
    47.         }   
    48.        
    49.     public void paint(Graphics g, JComponent c) {   
    50.         Rectangle clip = g.getClipBounds();   
    51.   
    52.         Rectangle bounds = table.getBounds();   
    53.         // account for the fact that the graphics has already been translated   
    54.         // into the table's bounds   
    55.         bounds.x = bounds.y = 0;   
    56.   
    57.     if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||   
    58.                 // this check prevents us from painting the entire table   
    59.                 // when the clip doesn't intersect our bounds at all   
    60.                 !bounds.intersects(clip)) {   
    61.   
    62.             paintDropLines(g);   
    63.         return;   
    64.     }   
    65.   
    66.         boolean ltr = table.getComponentOrientation().isLeftToRight();   
    67.   
    68.     Point upperLeft = clip.getLocation();   
    69.         if (!ltr) {   
    70.             upperLeft.x++;   
    71.         }   
    72.   
    73.     Point lowerRight = new Point(clip.x + clip.width - (ltr ? 1 : 0),   
    74.                                      clip.y + clip.height);   
    75.   
    76.         int rMin = table.rowAtPoint(upperLeft);   
    77.         int rMax = table.rowAtPoint(lowerRight);   
    78.         // This should never happen (as long as our bounds intersect the clip,   
    79.         // which is why we bail above if that is the case).   
    80.         if (rMin == -1) {   
    81.         rMin = 0;   
    82.         }   
    83.         // If the table does not have enough rows to fill the view we'll get -1.   
    84.         // (We could also get -1 if our bounds don't intersect the clip,   
    85.         // which is why we bail above if that is the case).   
    86.         // Replace this with the index of the last row.   
    87.         if (rMax == -1) {   
    88.         rMax = table.getRowCount()-1;   
    89.         }   
    90.   
    91.         int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);    
    92.         int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);           
    93.         // This should never happen.   
    94.         if (cMin == -1) {   
    95.         cMin = 0;   
    96.         }   
    97.     // If the table does not have enough columns to fill the view we'll get -1.   
    98.         // Replace this with the index of the last column.   
    99.         if (cMax == -1) {   
    100.         cMax = table.getColumnCount()-1;   
    101.         }   
    102.   
    103.         // Paint the grid.   
    104.         //paintGrid(g, rMin, rMax, cMin, cMax);   
    105.   
    106.         // Paint the cells.   
    107.     paintCells(g, rMin, rMax, cMin, cMax);   
    108.   
    109.         paintDropLines(g);   
    110.     }   
    111.        
    112.     private void paintDropLines(Graphics g) {   
    113.         JTable.DropLocation loc = table.getDropLocation();   
    114.         if (loc == null) {   
    115.             return;   
    116.         }   
    117.   
    118.         Color color = UIManager.getColor("Table.dropLineColor");   
    119.         Color shortColor = UIManager.getColor("Table.dropLineShortColor");   
    120.         if (color == null && shortColor == null) {   
    121.             return;   
    122.         }   
    123.   
    124.         Rectangle rect;   
    125.   
    126.         rect = getHDropLineRect(loc);   
    127.         if (rect != null) {   
    128.             int x = rect.x;   
    129.             int w = rect.width;   
    130.             if (color != null) {   
    131.                 extendRect(rect, true);   
    132.                 g.setColor(color);   
    133.                 g.fillRect(rect.x, rect.y, rect.width, rect.height);   
    134.             }   
    135.             if (!loc.isInsertColumn() && shortColor != null) {   
    136.                 g.setColor(shortColor);   
    137.                 g.fillRect(x, rect.y, w, rect.height);   
    138.             }   
    139.         }   
    140.   
    141.         rect = getVDropLineRect(loc);   
    142.         if (rect != null) {   
    143.             int y = rect.y;   
    144.             int h = rect.height;   
    145.             if (color != null) {   
    146.                 extendRect(rect, false);   
    147.                 g.setColor(color);   
    148.                 g.fillRect(rect.x, rect.y, rect.width, rect.height);   
    149.             }   
    150.             if (!loc.isInsertRow() && shortColor != null) {   
    151.                 g.setColor(shortColor);   
    152.                 g.fillRect(rect.x, y, rect.width, h);   
    153.             }   
    154.         }   
    155.     }   
    156.        
    157.     /*  
    158.      * Paints the grid lines within aRect, using the grid  
    159.      * color set with setGridColor. Paints vertical lines  
    160.      * if getShowVerticalLines() returns true and paints  
    161.      * horizontal lines if getShowHorizontalLines()  
    162.      * returns true.  
    163.      */  
    164.     private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {   
    165.         g.setColor(table.getGridColor());   
    166.   
    167.         Rectangle minCell = table.getCellRect(rMin, cMin, true);   
    168.         Rectangle maxCell = table.getCellRect(rMax, cMax, true);   
    169.         Rectangle damagedArea = minCell.union( maxCell );   
    170.   
    171.         if (table.getShowHorizontalLines()) {   
    172.             int tableWidth = damagedArea.x + damagedArea.width;   
    173.             int y = damagedArea.y;   
    174.             for (int row = rMin; row <= rMax; row++) {   
    175.                 y += table.getRowHeight(row);   
    176.                 g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);   
    177.             }   
    178.         }   
    179.         if (table.getShowVerticalLines()) {   
    180.             TableColumnModel cm = table.getColumnModel();   
    181.             int tableHeight = damagedArea.y + damagedArea.height;   
    182.             int x;   
    183.             if (table.getComponentOrientation().isLeftToRight()) {   
    184.                 x = damagedArea.x;   
    185.                 for (int column = cMin; column <= cMax; column++) {   
    186.                     int w = cm.getColumn(column).getWidth();   
    187.                     x += w;   
    188.                     g.drawLine(x - 10, x - 1, tableHeight - 1);   
    189.                 }   
    190.             } else {   
    191.                 x = damagedArea.x;   
    192.                 for (int column = cMax; column >= cMin; column--) {   
    193.                     int w = cm.getColumn(column).getWidth();   
    194.                     x += w;   
    195.                     g.drawLine(x - 10, x - 1, tableHeight - 1);   
    196.                 }   
    197.             }   
    198.         }   
    199.     }   
    200.        
    201.     private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {   
    202.         JTableHeader header = table.getTableHeader();   
    203.         TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();   
    204.   
    205.         TableColumnModel cm = table.getColumnModel();   
    206.         int columnMargin = cm.getColumnMargin();   
    207.             Rectangle cellRect;   
    208.         TableColumn aColumn;   
    209.         int columnWidth;   
    210.         if (table.getComponentOrientation().isLeftToRight()) {   
    211.             for(int row = rMin; row <= rMax; row++) {   
    212.                 if( table instanceof GridBagTable )   
    213.                     cellRect = ((GridBagTable)table).getGridCellRect(row, cMin, false);   
    214.                 else  
    215.                     cellRect = table.getCellRect(row, cMin, false);   
    216.                 for(int column = cMin; column <= cMax; column++) {   
    217.                     aColumn = cm.getColumn(column);   
    218.                     columnWidth = aColumn.getWidth();                                    
    219.                     //TODO   
    220.                     cellRect.width = columnWidth - columnMargin;   
    221.                     int oldHeight = cellRect.height;   
    222.                     if( table instanceof GridBagTable ){   
    223.                         if(((GridBagTable)table).getGridBagModel().getCellState( row, column) == GridBagModel.COVERED ) {   
    224.                             cellRect.width = 0;   
    225.                             cellRect.height = 0;   
    226.                         }   
    227.                         else{   
    228.                             int h = ((GridBagTable)table).getGridBagModel().getColumnGrid(row, column);   
    229.                             if( h >1 ){   
    230.                                 forint n=1; n
    231.                                     cellRect.width += cm.getColumn(column+n).getWidth();   
    232.                             }   
    233.                             int v = ((GridBagTable)table).getGridBagModel().getRowGrid(row, column);   
    234.                             if( v >1 ){   
    235.                                 forint n=1; n
    236.                                     cellRect.height += table.getRowHeight(row+n);   
    237.                             }   
    238.                         }              
    239.                     }                                                                          
    240.                     if (aColumn != draggedColumn) {   
    241.                         paintCell(g, cellRect, row, column);   
    242.                     }                          
    243.                     cellRect.height = oldHeight;                       
    244.                     cellRect.x += columnWidth;   
    245.                 }   
    246.             }   
    247.         } else {   
    248.             for(int row = rMin; row <= rMax; row++) {   
    249.                     cellRect = table.getCellRect(row, cMin, false);   
    250.                     aColumn = cm.getColumn(cMin);   
    251.                     if (aColumn != draggedColumn) {   
    252.                         columnWidth = aColumn.getWidth();   
    253.                         cellRect.width = columnWidth - columnMargin;   
    254.                         paintCell(g, cellRect, row, cMin);   
    255.                     }   
    256.                     for(int column = cMin+1; column <= cMax; column++) {   
    257.                         aColumn = cm.getColumn(column);   
    258.                         columnWidth = aColumn.getWidth();   
    259. //                      TODO   
    260.                         cellRect.width = columnWidth - columnMargin;   
    261.                         cellRect.x -= columnWidth;   
    262.                         if (aColumn != draggedColumn) {   
    263.                             paintCell(g, cellRect, row, column);   
    264.                         }   
    265.                 }   
    266.             }   
    267.         }   
    268.   
    269.             // Paint the dragged column if we are dragging.   
    270.             if (draggedColumn != null) {   
    271.             paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());   
    272.         }   
    273.   
    274.         // Remove any renderers that may be left in the rendererPane.   
    275.         rendererPane.removeAll();   
    276.         }   
    277.        
    278.     private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {   
    279.         if (table.isEditing() && table.getEditingRow()==row &&   
    280.                                  table.getEditingColumn()==column) {   
    281.             Component component = table.getEditorComponent();   
    282.         component.setBounds(cellRect);   
    283.             component.validate();   
    284.         }   
    285.         else {   
    286.             TableCellRenderer renderer = table.getCellRenderer(row, column);   
    287.             Component component = table.prepareRenderer(renderer, row, column);   
    288.                
    289.             if( component instanceof JComponent ){   
    290.                 ((JComponent)component).setBorder(BorderFactory.createLineBorder(Color.gray));   
    291.             }   
    292.             rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,   
    293.                                         cellRect.width, cellRect.height, true);              
    294.         }   
    295.     }   
    296.        
    297.     private Rectangle getHDropLineRect(JTable.DropLocation loc) {   
    298.         if (!loc.isInsertRow()) {   
    299.             return null;   
    300.         }   
    301.   
    302.         int row = loc.getRow();   
    303.         int col = loc.getColumn();   
    304.         if (col >= table.getColumnCount()) {   
    305.             col--;   
    306.         }   
    307.   
    308.         Rectangle rect = table.getCellRect(row, col, true);   
    309.   
    310.         if (row >= table.getRowCount()) {   
    311.             row--;   
    312.             Rectangle prevRect = table.getCellRect(row, col, true);   
    313.             rect.y = prevRect.y + prevRect.height;   
    314.         }   
    315.   
    316.         if (rect.y == 0) {   
    317.             rect.y = -1;   
    318.         } else {   
    319.             rect.y -= 2;   
    320.         }   
    321.   
    322.         rect.height = 3;   
    323.   
    324.         return rect;   
    325.     }   
    326.        
    327.     private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {   
    328.         int draggedColumnIndex = viewIndexForColumn(draggedColumn);   
    329.   
    330.         Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);   
    331.     Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);   
    332.   
    333.     Rectangle vacatedColumnRect = minCell.union(maxCell);   
    334.   
    335.     // Paint a gray well in place of the moving column.   
    336.     g.setColor(table.getParent().getBackground());   
    337.     g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,   
    338.            vacatedColumnRect.width, vacatedColumnRect.height);   
    339.   
    340.     // Move to the where the cell has been dragged.   
    341.     vacatedColumnRect.x += distance;   
    342.   
    343.     // Fill the background.   
    344.     g.setColor(table.getBackground());   
    345.     g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,   
    346.            vacatedColumnRect.width, vacatedColumnRect.height);   
    347.   
    348.     // Paint the vertical grid lines if necessary.   
    349.     if (table.getShowVerticalLines()) {   
    350.         g.setColor(table.getGridColor());   
    351.         int x1 = vacatedColumnRect.x;   
    352.         int y1 = vacatedColumnRect.y;   
    353.         int x2 = x1 + vacatedColumnRect.width - 1;   
    354.         int y2 = y1 + vacatedColumnRect.height - 1;   
    355.         // Left   
    356.         g.drawLine(x1-1, y1, x1-1, y2);   
    357.         // Right   
    358.         g.drawLine(x2, y1, x2, y2);   
    359.     }   
    360.   
    361.     for(int row = rMin; row <= rMax; row++) {   
    362.         // Render the cell value   
    363.         Rectangle r = table.getCellRect(row, draggedColumnIndex, false);   
    364.         r.x += distance;   
    365.         paintCell(g, r, row, draggedColumnIndex);   
    366.   
    367.         // Paint the (lower) horizontal grid line if necessary.   
    368.         if (table.getShowHorizontalLines()) {   
    369.         g.setColor(table.getGridColor());   
    370.         Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);   
    371.         rcr.x += distance;   
    372.         int x1 = rcr.x;   
    373.         int y1 = rcr.y;   
    374.         int x2 = x1 + rcr.width - 1;   
    375.         int y2 = y1 + rcr.height - 1;   
    376.         g.drawLine(x1, y2, x2, y2);   
    377.         }   
    378.     }   
    379.     }   
    380.        
    381.     private int viewIndexForColumn(TableColumn aColumn) {   
    382.         TableColumnModel cm = table.getColumnModel();   
    383.         for (int column = 0; column < cm.getColumnCount(); column++) {   
    384.             if (cm.getColumn(column) == aColumn) {   
    385.                 return column;   
    386.             }   
    387.         }   
    388.         return -1;   
    389.     }   
    390.        
    391.     private Rectangle extendRect(Rectangle rect, boolean horizontal) {   
    392.         if (rect == null) {   
    393.             return rect;   
    394.         }   
    395.   
    396.         if (horizontal) {   
    397.             rect.x = 0;   
    398.             rect.width = table.getWidth();   
    399.         } else {   
    400.             rect.y = 0;   
    401.   
    402.             if (table.getRowCount() != 0) {   
    403.                 Rectangle lastRect = table.getCellRect(table.getRowCount() - 10true);   
    404.                 rect.height = lastRect.y + lastRect.height;   
    405.             } else {   
    406.                 rect.height = table.getHeight();   
    407.             }   
    408.         }   
    409.   
    410.         return rect;   
    411.     }   
    412.        
    413.     private Rectangle getVDropLineRect(JTable.DropLocation loc) {   
    414.         if (!loc.isInsertColumn()) {   
    415.             return null;   
    416.         }   
    417.   
    418.         boolean ltr = table.getComponentOrientation().isLeftToRight();   
    419.         int col = loc.getColumn();   
    420.         Rectangle rect = table.getCellRect(loc.getRow(), col, true);   
    421.   
    422.         if (col >= table.getColumnCount()) {   
    423.             col--;   
    424.             rect = table.getCellRect(loc.getRow(), col, true);   
    425.             if (ltr) {   
    426.                 rect.x = rect.x + rect.width;   
    427.             }   
    428.         } else if (!ltr) {   
    429.             rect.x = rect.x + rect.width;   
    430.         }   
    431.   
    432.         if (rect.x == 0) {   
    433.             rect.x = -1;   
    434.         } else {   
    435.             rect.x -= 2;   
    436.         }   
    437.            
    438.         rect.width = 3;   
    439.   
    440.         return rect;   
    441.     }   
    442.   
    443. }  // End of Class BasicTableUI  
    package org.dxj.guitools.gridbagtable;
    
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.util.Enumeration;
    
    import javax.swing.BorderFactory;
    import javax.swing.JComponent;
    import javax.swing.JTable;
    import javax.swing.UIManager;
    import javax.swing.plaf.basic.BasicTableUI;
    import javax.swing.table.JTableHeader;
    import javax.swing.table.TableCellRenderer;
    import javax.swing.table.TableColumn;
    import javax.swing.table.TableColumnModel;
    
    public class GridBagTableUI extends BasicTableUI
    {
        public Dimension getPreferredSize(JComponent c) {
            long width = 0;
            Enumeration enumeration = table.getColumnModel().getColumns();
            while (enumeration.hasMoreElements()) {
                TableColumn aColumn = (TableColumn)enumeration.nextElement();
                width = width + aColumn.getPreferredWidth();
            }
            return createTableSize(width);
        }
        
        private Dimension createTableSize(long width) {
        	int height = 0;
        	int rowCount = table.getRowCount();
        	if (rowCount > 0 && table.getColumnCount() > 0) {
        	    Rectangle r = table.getCellRect(rowCount-1, 0, true);
        	    height = r.y + r.height;
        	}
        	// Width is always positive. The call to abs() is a workaround for
        	// a bug in the 1.1.6 JIT on Windows.
        	long tmp = Math.abs(width);
                if (tmp > Integer.MAX_VALUE) {
                    tmp = Integer.MAX_VALUE;
                }
        	return new Dimension((int)tmp, height);
            }
        
        public void paint(Graphics g, JComponent c) {
            Rectangle clip = g.getClipBounds();
    
            Rectangle bounds = table.getBounds();
            // account for the fact that the graphics has already been translated
            // into the table's bounds
            bounds.x = bounds.y = 0;
    
    	if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
                    // this check prevents us from painting the entire table
                    // when the clip doesn't intersect our bounds at all
                    !bounds.intersects(clip)) {
    
                paintDropLines(g);
    	    return;
    	}
    
            boolean ltr = table.getComponentOrientation().isLeftToRight();
    
    	Point upperLeft = clip.getLocation();
            if (!ltr) {
                upperLeft.x++;
            }
    
    	Point lowerRight = new Point(clip.x + clip.width - (ltr ? 1 : 0),
                                         clip.y + clip.height);
    
            int rMin = table.rowAtPoint(upperLeft);
            int rMax = table.rowAtPoint(lowerRight);
            // This should never happen (as long as our bounds intersect the clip,
            // which is why we bail above if that is the case).
            if (rMin == -1) {
    	    rMin = 0;
            }
            // If the table does not have enough rows to fill the view we'll get -1.
            // (We could also get -1 if our bounds don't intersect the clip,
            // which is why we bail above if that is the case).
            // Replace this with the index of the last row.
            if (rMax == -1) {
    	    rMax = table.getRowCount()-1;
            }
    
            int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight); 
            int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);        
            // This should never happen.
            if (cMin == -1) {
    	    cMin = 0;
            }
    	// If the table does not have enough columns to fill the view we'll get -1.
            // Replace this with the index of the last column.
            if (cMax == -1) {
    	    cMax = table.getColumnCount()-1;
            }
    
            // Paint the grid.
            //paintGrid(g, rMin, rMax, cMin, cMax);
    
            // Paint the cells.
    	paintCells(g, rMin, rMax, cMin, cMax);
    
            paintDropLines(g);
        }
        
        private void paintDropLines(Graphics g) {
            JTable.DropLocation loc = table.getDropLocation();
            if (loc == null) {
                return;
            }
    
            Color color = UIManager.getColor("Table.dropLineColor");
            Color shortColor = UIManager.getColor("Table.dropLineShortColor");
            if (color == null && shortColor == null) {
                return;
            }
    
            Rectangle rect;
    
            rect = getHDropLineRect(loc);
            if (rect != null) {
                int x = rect.x;
                int w = rect.width;
                if (color != null) {
                    extendRect(rect, true);
                    g.setColor(color);
                    g.fillRect(rect.x, rect.y, rect.width, rect.height);
                }
                if (!loc.isInsertColumn() && shortColor != null) {
                    g.setColor(shortColor);
                    g.fillRect(x, rect.y, w, rect.height);
                }
            }
    
            rect = getVDropLineRect(loc);
            if (rect != null) {
                int y = rect.y;
                int h = rect.height;
                if (color != null) {
                    extendRect(rect, false);
                    g.setColor(color);
                    g.fillRect(rect.x, rect.y, rect.width, rect.height);
                }
                if (!loc.isInsertRow() && shortColor != null) {
                    g.setColor(shortColor);
                    g.fillRect(rect.x, y, rect.width, h);
                }
            }
        }
        
        /*
         * Paints the grid lines within aRect, using the grid
         * color set with setGridColor. Paints vertical lines
         * if getShowVerticalLines() returns true and paints
         * horizontal lines if getShowHorizontalLines()
         * returns true.
         */
        private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {
            g.setColor(table.getGridColor());
    
            Rectangle minCell = table.getCellRect(rMin, cMin, true);
            Rectangle maxCell = table.getCellRect(rMax, cMax, true);
            Rectangle damagedArea = minCell.union( maxCell );
    
    		if (table.getShowHorizontalLines()) {
    			int tableWidth = damagedArea.x + damagedArea.width;
    			int y = damagedArea.y;
    			for (int row = rMin; row <= rMax; row++) {
    				y += table.getRowHeight(row);
    				g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);
    			}
    		}
    		if (table.getShowVerticalLines()) {
    			TableColumnModel cm = table.getColumnModel();
    			int tableHeight = damagedArea.y + damagedArea.height;
    			int x;
    			if (table.getComponentOrientation().isLeftToRight()) {
    				x = damagedArea.x;
    				for (int column = cMin; column <= cMax; column++) {
    					int w = cm.getColumn(column).getWidth();
    					x += w;
    					g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
    				}
    			} else {
    				x = damagedArea.x;
    				for (int column = cMax; column >= cMin; column--) {
    					int w = cm.getColumn(column).getWidth();
    					x += w;
    					g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
    				}
    			}
    		}
        }
        
        private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {
        	JTableHeader header = table.getTableHeader();
        	TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
    
        	TableColumnModel cm = table.getColumnModel();
        	int columnMargin = cm.getColumnMargin();
                Rectangle cellRect;
        	TableColumn aColumn;
        	int columnWidth;
        	if (table.getComponentOrientation().isLeftToRight()) {
        	    for(int row = rMin; row <= rMax; row++) {
        	    	if( table instanceof GridBagTable )
        	    		cellRect = ((GridBagTable)table).getGridCellRect(row, cMin, false);
        	    	else
        	    		cellRect = table.getCellRect(row, cMin, false);
                    for(int column = cMin; column <= cMax; column++) {
                        aColumn = cm.getColumn(column);
                        columnWidth = aColumn.getWidth();                                 
                        //TODO
                        cellRect.width = columnWidth - columnMargin;
                        int oldHeight = cellRect.height;
                        if( table instanceof GridBagTable ){
                        	if(((GridBagTable)table).getGridBagModel().getCellState( row, column) == GridBagModel.COVERED ) {
                            	cellRect.width = 0;
                            	cellRect.height = 0;
                            }
                        	else{
                        		int h = ((GridBagTable)table).getGridBagModel().getColumnGrid(row, column);
                            	if( h >1 ){
                            		for( int n=1; n1 ){
                            		for( int n=1; n= table.getColumnCount()) {
                col--;
            }
    
            Rectangle rect = table.getCellRect(row, col, true);
    
            if (row >= table.getRowCount()) {
                row--;
                Rectangle prevRect = table.getCellRect(row, col, true);
                rect.y = prevRect.y + prevRect.height;
            }
    
            if (rect.y == 0) {
                rect.y = -1;
            } else {
                rect.y -= 2;
            }
    
            rect.height = 3;
    
            return rect;
        }
        
        private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
            int draggedColumnIndex = viewIndexForColumn(draggedColumn);
    
            Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
    	Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
    
    	Rectangle vacatedColumnRect = minCell.union(maxCell);
    
    	// Paint a gray well in place of the moving column.
    	g.setColor(table.getParent().getBackground());
    	g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
    		   vacatedColumnRect.width, vacatedColumnRect.height);
    
    	// Move to the where the cell has been dragged.
    	vacatedColumnRect.x += distance;
    
    	// Fill the background.
    	g.setColor(table.getBackground());
    	g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
    		   vacatedColumnRect.width, vacatedColumnRect.height);
    
    	// Paint the vertical grid lines if necessary.
    	if (table.getShowVerticalLines()) {
    	    g.setColor(table.getGridColor());
    	    int x1 = vacatedColumnRect.x;
    	    int y1 = vacatedColumnRect.y;
    	    int x2 = x1 + vacatedColumnRect.width - 1;
    	    int y2 = y1 + vacatedColumnRect.height - 1;
    	    // Left
    	    g.drawLine(x1-1, y1, x1-1, y2);
    	    // Right
    	    g.drawLine(x2, y1, x2, y2);
    	}
    
    	for(int row = rMin; row <= rMax; row++) {
    	    // Render the cell value
    	    Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
    	    r.x += distance;
    	    paintCell(g, r, row, draggedColumnIndex);
    
    	    // Paint the (lower) horizontal grid line if necessary.
    	    if (table.getShowHorizontalLines()) {
    		g.setColor(table.getGridColor());
    		Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
    		rcr.x += distance;
    		int x1 = rcr.x;
    		int y1 = rcr.y;
    		int x2 = x1 + rcr.width - 1;
    		int y2 = y1 + rcr.height - 1;
    		g.drawLine(x1, y2, x2, y2);
    	    }
    	}
        }
        
        private int viewIndexForColumn(TableColumn aColumn) {
            TableColumnModel cm = table.getColumnModel();
            for (int column = 0; column < cm.getColumnCount(); column++) {
                if (cm.getColumn(column) == aColumn) {
                    return column;
                }
            }
            return -1;
        }
        
        private Rectangle extendRect(Rectangle rect, boolean horizontal) {
            if (rect == null) {
                return rect;
            }
    
            if (horizontal) {
                rect.x = 0;
                rect.width = table.getWidth();
            } else {
                rect.y = 0;
    
                if (table.getRowCount() != 0) {
                    Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
                    rect.height = lastRect.y + lastRect.height;
                } else {
                    rect.height = table.getHeight();
                }
            }
    
            return rect;
        }
        
        private Rectangle getVDropLineRect(JTable.DropLocation loc) {
            if (!loc.isInsertColumn()) {
                return null;
            }
    
            boolean ltr = table.getComponentOrientation().isLeftToRight();
            int col = loc.getColumn();
            Rectangle rect = table.getCellRect(loc.getRow(), col, true);
    
            if (col >= table.getColumnCount()) {
                col--;
                rect = table.getCellRect(loc.getRow(), col, true);
                if (ltr) {
                    rect.x = rect.x + rect.width;
                }
            } else if (!ltr) {
                rect.x = rect.x + rect.width;
            }
    
            if (rect.x == 0) {
                rect.x = -1;
            } else {
                rect.x -= 2;
            }
            
            rect.width = 3;
    
            return rect;
        }
    
    }  // End of Class BasicTableUI
    

      测试代码:

    Java代码 复制代码  收藏代码
    1. import java.awt.BorderLayout;   
    2. import java.awt.event.ActionEvent;   
    3. import java.awt.event.ActionListener;   
    4.   
    5. import javax.swing.JButton;   
    6. import javax.swing.JFrame;   
    7. import javax.swing.JScrollPane;   
    8. import javax.swing.table.DefaultTableModel;   
    9.   
    10. import com.jrf.jgrid.guitools.gridbagtable.GridBagTable;   
    11.   
    12.   
    13. public class Test implements ActionListener{   
    14.        
    15.     GridBagTable table;   
    16.     public Test()   
    17.     {   
    18.         JFrame d = new JFrame();   
    19.         DefaultTableModel model = new DefaultTableModel(5,5);   
    20.            
    21.         table = new GridBagTable(model);   
    22.         table.setRowHeight(20);   
    23.            
    24.         JScrollPane pane = new JScrollPane(table);   
    25.         d.getContentPane().add(pane, BorderLayout.CENTER);   
    26.         JButton btn = new JButton("合并/拆分");   
    27.         d.getContentPane().add(btn, BorderLayout.NORTH);   
    28.         btn.addActionListener(this);   
    29.         d.setBounds(00400400);   
    30.         d.setVisible(true);   
    31.     }   
    32.        
    33.     public static void main(String[] fsd){   
    34.         new Test();   
    35.     }   
    36.        
    37.     public void actionPerformed(ActionEvent e) {   
    38.         table.mergeCells(table.getSelectedRows(), table.getSelectedColumns());   
    39.     }   
    40. }  

你可能感兴趣的:(转载,SWING)