浏览 13529 次
精华帖 (6) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-18
最后修改:2010-08-18
N年前在网上参加了一个JavaSwing的招聘上机考试。招聘方要求开发一个类似EXCEL支持单元格合并的JTable。差不多用了5天的时间提交代码,最后被告知测试通过,我提出是否可做兼职,对方回复需要到上海做全职开发,最后也就放弃了。最近公司的一个项目中需要用到以前的代码,偶又重构了一次,设计思想来源于ListSelectionModel。
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()); } }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-08-20
写得蛮好,代码有点长,没能仔细看,先支持一下
|
|
返回顶楼 | |
发表时间:2010-08-24
这个很猛,顶下。JTable是学好swing重中之重啊
|
|
返回顶楼 | |
发表时间:2010-09-07
曾经用js写过一个合并,拆分
很麻烦。。。 |
|
返回顶楼 | |
发表时间:2010-09-08
呵呵,不错,好东西,我们项目中也用到了,
|
|
返回顶楼 | |
发表时间:2011-04-17
后輩來取經了
|
|
返回顶楼 | |
发表时间:2011-08-10
下了下来,发现包里一个类都么有!
|
|
返回顶楼 | |
发表时间:2011-08-12
过于繁琐吧
|
|
返回顶楼 | |
发表时间:2011-08-13
太长了,以后要用再看
|
|
返回顶楼 | |