`
珊珊来了
  • 浏览: 11420 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

阅读更多

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

 



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

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

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 15860102@qq.com
 */
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<cols; n++)
			cellRect.width += cm.getColumn(column+n).getWidth();
    	int rows = gridBagModel.getRowGrid(row, column);
    	for( int n=1; n<rows; n++)
			cellRect.height += getRowHeight(row+n);
    	return cellRect;		 
	}
	
	public void tableChanged(TableModelEvent e){
		super.tableChanged(e);
		//TODO
	}
	
	public boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn){
		if( gridBagModel.mergeCells(startRow, endRow, startColumn, endColumn)){
			repaint();
			return true;
		}	
		return false;
	}
	 
	public boolean mergeCells(int[] rows, int[] columns){
		if( gridBagModel.mergeCells(rows, columns)){
			repaint();
			return true;
		}	
		return false;
	}
	
	public boolean spliteCellAt(int row, int column){
		if( gridBagModel.spliteCellAt(row, column)){
			repaint();
			return true;
		}
		return false;
	}
	
    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
    	if( gridBagModel.getCellState( rowIndex , columnIndex ) != GridBagModel.COVERED  )
    		super.changeSelection(rowIndex, columnIndex, toggle, extend);
		Point p;
		for( int row = rowIndex; row >= 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);        
    }
}
 
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();
}
 
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<List<Point>> gridInfo;
	
	DefaultGridBagTableModel(AbstractTableModel model){
		gridInfo = new Vector<List<Point>>();
		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<List<Point>>();
		else
			gridInfo.clear();
		
		if( model == null )
			return;
		
		//初始化,每个格子占的格子数为(1,1);
		for(int row=model.getRowCount(); --row>=0;){
			List<Point> infos = new Vector<Point>();
			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<rows.length-1; index++){
			if( rows[index+1] - rows[index] > 1 )
				return false;
		}
		Arrays.sort(columns);
		for(int index=0; index<columns.length-1; index++){
			if( columns[index+1] - columns[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<Point> 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<Point> 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<Point> 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<Point> 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<Point> 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<point.y; a++){
						for(int b=0; b<point.x; b++){
							setGrid(row+a, column+b, getDefaultPoint());
						}
					}
				}
				else{
					gridRow.set(column, getDefaultPoint());
				}
				return true;
			}	
		}
		return false;
	}
	
	@Override
	/**
	 * table中发生行的添加和删除的时候需要修改该模型
	 */
	public void tableChanged(TableModelEvent e) {
		//TODO
	}
	
	@Override
	public boolean mergeCells(int[] rows, int[] columns) {
		if( !canMergeCells(rows, columns) )
			return false;
		Arrays.sort(rows);
		Arrays.sort(columns);
		return mergeCells(rows[0],rows[rows.length-1],columns[0],columns[columns.length-1]);
	}

	@Override
	public boolean mergeCells(int startRow, int endRow, int startColumn, int endColumn) {
		setGrid(startRow, startColumn, new Point(endColumn-startColumn+1, endRow-startRow+1)); 
		for(int row=startRow; row<=endRow; row++){
			for(int col=startColumn; col<=endColumn; col++){
				if(row==startRow&&col==startColumn)
					continue;
				else
					setGrid(row, col, new Point(COVERED,COVERED)); 
			}
		}
		return true;
	}
	
	public String toString(){
		if( gridInfo == null )
			return "";
		StringBuffer sb = new StringBuffer();
		for(List<Point> rowInfo : gridInfo ){
			for(Point grid : rowInfo){
				sb.append("["+grid.x+","+grid.y+"], ");
			}
			sb.append("\n");
		}
		return sb.toString();
	}
}
 
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<TableColumn> 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 <I>aRect</I>, using the grid
     * color set with <I>setGridColor</I>. Paints vertical lines
     * if <code>getShowVerticalLines()</code> returns true and paints
     * horizontal lines if <code>getShowHorizontalLines()</code>
     * 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; n<h; n++)
                        			cellRect.width += cm.getColumn(column+n).getWidth();
                        	}
                        	int v = ((GridBagTable)table).getGridBagModel().getRowGrid(row, column);
                        	if( v >1 ){
                        		for( int n=1; n<v; n++)
                        			cellRect.height += table.getRowHeight(row+n);
                        	}
                    	}          	
                    }                                                                       
                    if (aColumn != draggedColumn) {
                        paintCell(g, cellRect, row, column);
                    }                       
                	cellRect.height = oldHeight;                   	
                    cellRect.x += columnWidth;
            	}
    	    }
    	} else {
    	    for(int row = rMin; row <= rMax; row++) {
                    cellRect = table.getCellRect(row, cMin, false);
                    aColumn = cm.getColumn(cMin);
                    if (aColumn != draggedColumn) {
                        columnWidth = aColumn.getWidth();
                        cellRect.width = columnWidth - columnMargin;
                        paintCell(g, cellRect, row, cMin);
                    }
                    for(int column = cMin+1; column <= cMax; column++) {
                        aColumn = cm.getColumn(column);
                        columnWidth = aColumn.getWidth();
//                      TODO
                        cellRect.width = columnWidth - columnMargin;
                        cellRect.x -= columnWidth;
                        if (aColumn != draggedColumn) {
                            paintCell(g, cellRect, row, column);
                        }
            	}
    	    }
    	}

            // Paint the dragged column if we are dragging.
            if (draggedColumn != null) {
    	    paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());
    	}

    	// Remove any renderers that may be left in the rendererPane.
    	rendererPane.removeAll();
        }
    
    private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
        if (table.isEditing() && table.getEditingRow()==row &&
                                 table.getEditingColumn()==column) {
            Component component = table.getEditorComponent();
	    component.setBounds(cellRect);
            component.validate();
        }
        else {
            TableCellRenderer renderer = table.getCellRenderer(row, column);
            Component component = table.prepareRenderer(renderer, row, column);
            
            if( component instanceof JComponent ){
            	((JComponent)component).setBorder(BorderFactory.createLineBorder(Color.gray));
            }
            rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
                                        cellRect.width, cellRect.height, true);           
        }
    }
    
    private Rectangle getHDropLineRect(JTable.DropLocation loc) {
        if (!loc.isInsertRow()) {
            return null;
        }

        int row = loc.getRow();
        int col = loc.getColumn();
        if (col >= 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

  测试代码:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;

import com.jrf.jgrid.guitools.gridbagtable.GridBagTable;


public class Test implements ActionListener{
	
	GridBagTable table;
	public Test()
	{
		JFrame d = new JFrame();
		DefaultTableModel model = new DefaultTableModel(5,5);
		
		table = new GridBagTable(model);
		table.setRowHeight(20);
		
		JScrollPane pane = new JScrollPane(table);
		d.getContentPane().add(pane, BorderLayout.CENTER);
		JButton btn = new JButton("合并/拆分");
		d.getContentPane().add(btn, BorderLayout.NORTH);
		btn.addActionListener(this);
		d.setBounds(0, 0, 400, 400);
		d.setVisible(true);
	}
	
	public static void main(String[] fsd){
		new Test();
	}
	
	public void actionPerformed(ActionEvent e) {
		table.mergeCells(table.getSelectedRows(), table.getSelectedColumns());
	}
}
 

 

分享到:
评论
8 楼 jsruth 2013-04-26  
感谢分享,学习啦
7 楼 jtlaaa 2012-07-02  
6 楼 Atlantisbai 2012-06-14  
很好的东东,楼主很无私呀,哈哈!!
5 楼 lg_asus 2011-04-17  
后輩來取經了
4 楼 tiger860709 2010-09-08  
呵呵,不错,好东西,我们项目中也用到了,
3 楼 su1216 2010-09-07  
曾经用js写过一个合并,拆分
很麻烦。。。
2 楼 iyjc2004 2010-08-24  
这个很猛,顶下。JTable是学好swing重中之重啊
1 楼 daimojingdeyu 2010-08-20  
写得蛮好,代码有点长,没能仔细看,先支持一下

相关推荐

    Swing JTable组件设置单元格合并

    Swing JTable组件设置单元格合并,内置Test测试类,核心API GridBagTable tasktable = new GridBagTable(model); tasktable.mergeCells(startRow, endRow, 0, 0);

    swing 合并单元格的表格

    `CombineTable.java`可能是自定义的JTable子类,它扩展了`javax.swing.JTable`,并可能包含一些特定于合并单元格的方法或属性。这个类可以用来协调UI、渲染器和数据模型之间的通信,确保它们在处理合并单元格时保持...

    JTable合并单元格

    当你需要在`JTable`中实现特定的布局或者展示特殊格式的数据时,可能会遇到需要合并单元格的需求。例如,为了创建一个标题行或列,或者在某些情况下合并具有相同数据的单元格以减少重复,合并单元格就显得尤为重要。...

    swing Table合并单元格

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

    java 单元格合并

    首先,我们要区分两个主要场景:在GUI应用程序(如JavaFX或Swing)中合并单元格与在处理Excel文件(使用Apache POI)时合并单元格。这两种情况的方法略有不同。 1. **JavaFX或Swing中的单元格合并** 在JavaFX中,...

    JTable表头合并

    在Java Swing应用开发中,`JTable`是一个非常重要的组件,用于展示二维表格数据。它提供了丰富的功能,如数据编辑、排序、选择等。而"JTable表头合并"是Swing中的一个高级特性,允许开发者创建具有复杂结构的表头,...

    复杂JTable-跨列表头

    在Java Swing库中,JTable是一个非常重要的组件,用于显示和操作二维数据集。这个组件在用户界面设计中广泛使用,因为它提供了丰富的交互性,包括排序、选择和编辑表格数据。"复杂JTable-跨列表头"是一个特殊实现,...

    swing jtable 合并

    当我们谈论“Swing JTable 合并”,通常是指在`JTable`中合并单元格,以实现更复杂的布局或者展示具有汇总信息的表格。 在`JTable`中,合并单元格涉及到两个主要方面:行合并和列合并。行合并通常用于显示具有多个...

    swing 中Jtable例子

    在Java的Swing库中,`JTable`是用于创建数据网格视图的重要组件,它允许用户以表格的形式展示和操作数据。`JTable`在GUI应用中非常常见,尤其适用于展示结构化数据,比如数据库记录或者报表。在这个例子中,我们将...

    复杂JTable(复杂表头、跨行列表体)

    `getValueAt()`方法需要根据逻辑数据来返回正确的单元格值,包括合并单元格的情况。 **3. 示例代码** 下面是一段简单的代码示例,展示了如何创建一个具有复杂表头和跨行列表体的`JTable`: ```java import javax....

    SWING表头合并

    这可能涉及计算合并单元格的总宽度,并相应地调整相关列的宽度。 以下是一个简单的源码示例,展示了如何实现表头合并: ```java public class CustomTableHeaderRenderer extends DefaultTableHeaderCellRenderer ...

    netbeans jtable 复杂表头的实现方法

    例如,我们可能需要检查当前列的索引,并根据索引来决定是否合并单元格。 2. **设置表头渲染器**: 创建了自定义渲染器后,将其设置到`JTableHeader`上。可以使用`JTableHeader.setDefaultRenderer`方法来完成此...

    MulitiTable

    总结来说,实现JTable的单元格合并需要对Swing组件模型有深入理解,尤其是JTable的工作原理。通过定制CellRenderer和调整表格模型,我们可以创造出满足各种需求的表格布局。"MulitiTable"项目提供了一个很好的示例,...

    实用Swing 实例

    通过学习以上知识点,你将能够创建一个能够合并单元格的`JTable`实例。在压缩包文件中提供的"Swing实例下载"很可能是包含了这些功能的示例代码,可以帮助你更好地理解和实践这个功能。记得阅读和分析代码,理解每个...

    Swing JTable工厂(table4j)

    4. **高级功能**:如行列拖放、分页、冻结列、合并单元格、自定义列宽等。 5. **事件处理**:可能提供了更加方便的事件监听和处理机制,使得对用户交互的响应更加简单。 6. **国际化支持**:方便进行多语言切换。 7....

    JTable实例大全

    在Java编程领域,Swing库是用于创建图形用户界面(GUI)的重要工具,而`JTable`是Swing中一个核心组件,它用于显示和编辑表格数据。`JTable`实例大全提供了各种实用示例,涵盖了`JTable`的高级功能,如合并表头和...

    java

    从压缩包子文件的文件名“表头合并单元格_ JTable Groupable TableHeader - Keep Fighting - 博客频道 - CSDN_NET.mht”来看,这可能是一个关于Java Swing组件JTable的专题。JTable是Java GUI编程中用于展示表格数据...

    jTable的使用

    **jTable是Java Swing库中的一个组件,用于在应用程序中展示和操作表格数据。它提供了丰富的功能,包括数据编辑、排序、过滤以及自定义显示等。深入学习jTable的使用,能够帮助开发者创建用户友好的界面,使得数据的...

Global site tag (gtag.js) - Google Analytics