java jtable 单元格合并_JTable合并单元格

这篇博客介绍了一个Java程序,它展示了如何使用JTable组件来合并指定列中连续相同值的单元格。通过CombineData类和CombineTable类的组合,实现了表格的单元格合并功能,包括计算合并范围、设置单元格渲染器以禁用编辑和选择,以及自定义表格UI以正确绘制合并后的单元格。此外,还提供了一个名为CombineColumnRender的渲染器类,确保合并列的单元格不可选中和聚焦。
摘要由CSDN通过智能技术生成

JTable单元格合并

合并指定的一列或几列中行连续相同的单元格的值。

效果如下

2072069.html

df5a92f6c4c513357c39fe7b66ad2e32.png

0840035e232c02eadaca2f80d95c0d9b.png

CombineData.java

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

public class CombineData {

public ArrayList combineColumns = new ArrayList();//用于保存需要合并的列号

private String[][] datas;//table的数据,用来计算合并的单元格

private ArrayList> rowPoss;

private ArrayList> rowCounts;

public CombineData() {

}

public CombineData(String[][] datas, int... combineColumns) {

this.datas = datas;

for (int i = 0; i < combineColumns.length; i++) {

if (combineColumns[i] < 0) {

continue;

}

this.combineColumns.add(combineColumns[i]);

}

process();

}

public CombineData(String[][] datas, List combineColumns) {

this.datas = datas;

for (Integer column : combineColumns) {

if (column < 0) {

continue;

}

this.combineColumns.add(column);

}

process();

}

public void initData(String[][] datas, int... combineColumns) {

this.datas = datas;

this.combineColumns.clear();

for (int i = 0; i < combineColumns.length; i++) {

if (combineColumns[i] < 0) {

continue;

}

this.combineColumns.add(combineColumns[i]);

}

process();

}

public void initData(String[][] datas, List combineColumns) {

this.datas = datas;

this.combineColumns.clear();

for (Integer column : combineColumns) {

if (column < 0) {

continue;

}

this.combineColumns.add(column);

}

process();

}

private void process() {

rowPoss = new ArrayList>();

rowCounts = new ArrayList>();

for (Integer integer : combineColumns) {

HashMap rowPos = new HashMap();

HashMap rowCount = new HashMap();

String pre = "";

int count = 0;

int start = 0;

for (int i = 0; i < datas.length; i++) {

String[] data = datas[i];

if (pre.equals(data[integer])) {

count++;

} else {

rowCount.put(start, count);

pre = data[integer];

count = 1;

start = i;

}

rowPos.put(i, start);

}

rowCount.put(start, count);

rowPoss.add(rowPos);

rowCounts.add(rowCount);

}

}

/**

* 返回table中row行column列单元格所跨行数

*/

public int span(int row, int column) {

int index = combineColumns.lastIndexOf(column);

if (index != -1) {

return rowCounts.get(index).get(rowPoss.get(index).get(row));

} else {

return 1;

}

}

/**

* 返回table中row行column列单元格所在的合并单元格的起始行位置

*/

public int visibleCell(int row, int column) {

int index = combineColumns.lastIndexOf(column);

if ((index != -1) && row > -1) {

return rowPoss.get(index).get(row);

} else {

return row;

}

}

}

CombineTable.java

import javax.swing.*;

import java.awt.*;

import javax.swing.table.TableColumn;

import javax.swing.table.TableModel;

public class CombineTable extends JTable {

public CombineData combineData;

public CombineTable(TableModel tableModel) {

super(tableModel);

super.setUI(new CombineTableUI());

}

public CombineTable(CombineData combineData, TableModel tableModel) {

super(tableModel);

this.combineData = combineData;

for (Integer column : combineData.combineColumns) {

TableColumn tableColumn = super.columnModel.getColumn(column);

tableColumn.setCellRenderer(new CombineColumnRender());

}

super.setUI(new CombineTableUI());

}

public void setCombineData(CombineData combineData) {

this.combineData = combineData;

for (Integer column : combineData.combineColumns) {

TableColumn tableColumn = super.columnModel.getColumn(column);

tableColumn.setCellRenderer(new CombineColumnRender());

}

}

@Override

public Rectangle getCellRect(int row, int column, boolean includeSpacing) {

// required because getCellRect is used in JTable constructor

if (combineData == null) {

return super.getCellRect(row, column, includeSpacing);

}

// add widths of all spanned logical cells

int sk = combineData.visibleCell(row, column);

//Rectangle r1 = super.getCellRect(row, sk, includeSpacing);

Rectangle rect1 = super.getCellRect(sk, column, includeSpacing);

if (combineData.span(sk, column) != 1) {

for (int i = 1; i < combineData.span(sk, column); i++) {

//r1.width += getColumnModel().getColumn(sk + i).getWidth();

rect1.height += this.getRowHeight(sk + i);

}

}

return rect1;

}

@Override

public int rowAtPoint(Point p) {

int column = super.columnAtPoint(p);

// -1 is returned by columnAtPoint if the point is not in the table

if (column < 0) {

return column;

}

int row = super.rowAtPoint(p);

return combineData.visibleCell(row, column);

}

@Override

public boolean isCellEditable(int row, int column) {

if (combineData.combineColumns.contains(column)) {

return false;

}

return super.isCellEditable(row, column);

}

@Override

public boolean isCellSelected(int row, int column) {

if (combineData.combineColumns.contains(column)) {

return false;

}

return super.isCellSelected(row, column);

}

}

CombineTableUI.java

import javax.swing.table.*;

import javax.swing.plaf.basic.*;

import java.awt.*;

import javax.swing.*;

class CombineTableUI extends BasicTableUI {

@Override

public void paint(Graphics g, JComponent c) {

Rectangle r = g.getClipBounds();

rendererPane.removeAll();

int firstCol = table.columnAtPoint(new Point(r.x, 0));

int lastCol = table.columnAtPoint(new Point(r.x + r.width, 0));

// -1 is a flag that the ending point is outside the table

if (lastCol < 0) {

lastCol = table.getColumnCount() - 1;

}

for (int i = firstCol; i <= lastCol; i++) {

paintCol(i, g);

}

paintGrid(g, 0, table.getRowCount() - 1, 0, table.getColumnCount() - 1);

}

private void paintCol(int col, Graphics g) {

Rectangle r = g.getClipBounds();

for (int i = 0; i < table.getRowCount(); i++) {

Rectangle r1 = table.getCellRect(i, col, true);

if (r1.intersects(r)) // at least a part is visible

{

int sk = ((CombineTable) table).combineData.visibleCell(i, col);

paintCell(sk, col, g, r1);

// increment the column counter

i += ((CombineTable) table).combineData.span(sk, col) - 1;

}

}

}

private void paintCell(int row, int column, Graphics g, Rectangle area) {

int verticalMargin = table.getRowMargin();

int horizontalMargin = table.getColumnModel().getColumnMargin();

area.setBounds(area.x + horizontalMargin / 2, area.y + verticalMargin / 2, area.width - horizontalMargin, area.height - verticalMargin);

if (table.isEditing() && table.getEditingRow() == row && table.getEditingColumn() == column) {

Component component = table.getEditorComponent();

component.setBounds(area);

component.validate();

} else {

TableCellRenderer renderer = table.getCellRenderer(row, column);

Component component = table.prepareRenderer(renderer, row, column);

if (component.getParent() == null) {

rendererPane.add(component);

}

rendererPane.paintComponent(g, component, table, area.x, area.y,

area.width, area.height, 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()) {

CombineData cMap = ((CombineTable) table).combineData;

for (int row = rMin; row <= rMax; row++) {

for (int column = cMin; column <= cMax; column++) {

Rectangle cellRect = table.getCellRect(row, column, true);

if (cMap.combineColumns.contains(column)) {

int visibleCell = cMap.visibleCell(row, column);

int span = cMap.span(row, column);

if (span > 1 && row < visibleCell + span - 1) {

} else {

g.drawLine(cellRect.x, cellRect.y + cellRect.height - 1, cellRect.x + cellRect.width - 1, cellRect.y + cellRect.height - 1);

}

} else {

g.drawLine(cellRect.x, cellRect.y + cellRect.height - 1, cellRect.x + cellRect.width - 1, cellRect.y + cellRect.height - 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);

}

}

}

}

}

CombineColumnRender.java

import java.awt.Component;

import javax.swing.JTable;

import javax.swing.table.DefaultTableCellRenderer;

/**

* 设置需要合并的列的单元格不能被选中,不能聚焦

* @author hualun-alan

*/

class CombineColumnRender extends DefaultTableCellRenderer {

@Override

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

CombineTable cTable = (CombineTable) table;

if (cTable.combineData.combineColumns.contains(column)) {

hasFocus = false;

}

return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

}

}

Test.java

import java.util.ArrayList;

import javax.swing.*;

import javax.swing.table.*;

public class Test {

public static void main(String args[]) {

JFrame jf = new JFrame("Cell Combine Table");

JTable cTable = getTable1();

jf.getContentPane().add(new JScrollPane(cTable));

jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

jf.setSize(500, 500);

jf.setVisible(true);

}

private static CombineTable getTable1() {

String[][] datas = new String[10][6];

for (int i = 0; i < datas.length; i++) {

String[] data = datas[i];

for (int j = 0; j < data.length; j++) {

data[j] = "";

}

data[0] = String.valueOf((int) (i / 3));

}

ArrayList combineColumns = new ArrayList();

combineColumns.add(0);

CombineData m = new CombineData(datas, combineColumns);

DefaultTableModel tm = new DefaultTableModel(datas, new String[]{"1", "2", "3", "4", "5"});

CombineTable cTable = new CombineTable(m, tm);

TableColumn column = cTable.getColumnModel().getColumn(0);

column.setCellRenderer(new CombineColumnRender());

column.setWidth(50);

column.setMaxWidth(50);

column.setMinWidth(50);

cTable.setCellSelectionEnabled(true);

return cTable;

}

private static CombineTable getTable2() {

String[][] datas = new String[10][6];

for (int i = 0; i < datas.length; i++) {

String[] data = datas[i];

for (int j = 0; j < data.length; j++) {

data[j] = "";

}

data[0] = String.valueOf((int) (i / 4));

data[1] = String.valueOf((int) (i / 2));

}

CombineData m = new CombineData(datas, 0, 1);

DefaultTableModel tm = new DefaultTableModel(datas, new String[]{"1", "2", "3", "4", "5"});

CombineTable cTable = new CombineTable(m, tm);

TableColumnModel columnModel = cTable.getColumnModel();

for (Integer integer : m.combineColumns) {

TableColumn column = columnModel.getColumn(integer);

column.setCellRenderer(new CombineColumnRender());

column.setWidth(50);

column.setMaxWidth(50);

column.setMinWidth(50);

}

cTable.setCellSelectionEnabled(true);

return cTable;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值