Java 如何合并 DefaultTableModel/JTable 中的单元格?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21856733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:05:43  来源:igfitidea点击:

How to merge cell in DefaultTableModel/JTable?

javaswingjtabletablecellrendererjtableheader

提问by Nikhil Chilwant

I searched a lot and got some answers for this Q. but many of them referred to links which give 404 error. I want to make table like this:

我搜索了很多,得到了一些关于这个问题的答案。但其中很多都提到了给出 404 错误的链接。我想制作这样的表格:

No. of cells to be merged is not fixed

要合并的单元格数量不固定

Is there any method in java for this?

java中有什么方法可以解决这个问题吗?

采纳答案by tenorsax

MultiSpanCellTableExampledemonstrates how to merge cells by creating a custom TableUI. There seem to be a problem in this example that causes StackOverflowError, at least in Java 6. To fix this, inside AttributiveCellTableModel.setDataVector()replace:

MultiSpanCellTableExample演示了如何通过创建自定义TableUI. 在这个例子中似乎有一个问题导致StackOverflowError,至少在 Java 6 中。要解决这个问题,请在内部AttributiveCellTableModel.setDataVector()替换:

setColumnIdentifiers(columnNames);

with:

和:

this.columnIdentifiers = columnNames;

IE:

IE:

public void setDataVector(Vector newData, Vector columnNames) {
    if (newData == null)
        throw new IllegalArgumentException(
                "setDataVector() - Null parameter");
    dataVector = new Vector(0);
    // setColumnIdentifiers(columnNames);
    this.columnIdentifiers = columnNames;
    dataVector = newData;

    cellAtt = new DefaultCellAttribute(dataVector.size(),
            columnIdentifiers.size());

    newRowsAdded(new TableModelEvent(this, 0, getRowCount() - 1,
            TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
}

The problem is that setColumnIdentifierscalls into setDataVectorhence triggering the StackOverflowError. Once fixed, this is how the example looks like:

问题是setColumnIdentifiers调用 intosetDataVector从而触发了StackOverflowError. 修复后,示例如下所示:

enter image description here

在此处输入图片说明

There is also a ready solution from JIDE, unfortunately it is not free. Here is for example CellSpanTable:

JIDE也有现成的解决方案,不幸的是它不是免费的。例如CellSpanTable

enter image description here

在此处输入图片说明

回答by Pedro Lima

MultiCellSpanTableExampleis fine, but it has a little problem that can become a huge problem if your table has too many columns. As you can see in the examplegiven by tenorsax, apparently each table column has an extra pixel in their width. Those additional pixels add up, making each column more displaced than the last.

MultiCellSpanTableExample很好,但它有一个小问题,如果您的表有太多列,它可能会成为一个大问题。正如您在Tenorsax 给出的示例中所见,显然每个表格列的宽度都有一个额外的像素。这些额外的像素加起来,使每一列比上一列移位更多。

I could simply fix that by replacing the line:

我可以通过替换该行来简单地解决这个问题:

cellFrame.width = aColumn.getWidth() + columnMargin;

with:

和:

cellFrame.width = aColumn.getWidth() + columnMargin - 1;

I know nobody asked, but I hope this helps someone. :)

我知道没有人问过,但我希望这对某人有所帮助。:)

回答by Friedolin

Use a custom TableCellRenderer

使用自定义 TableCellRenderer

import java.awt.Color;
import java.awt.Component;

import javax.swing.BorderFactory;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;

public class HeaderRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
TableCellRenderer renderer;

public HeaderRenderer(JTable table) {
  renderer = table.getTableHeader().getDefaultRenderer();
}

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

super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
switch (col) {
case 0:
  setBorder(BorderFactory.createMatteBorder(1, 1, 1, 0, Color.LIGHT_GRAY));
break;
case 1:
  setBorder(BorderFactory.createMatteBorder(1, 0, 1, 1, Color.LIGHT_GRAY));
break;
default:
  setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY));
break;
}
  return this;
}
}

from oracle doc

来自甲骨文文档

import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class SimpleTableDemo extends JPanel {
private static final long serialVersionUID = 1L;
public SimpleTableDemo() {
super(new GridLayout(1, 0));

String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" };

    Object[][] data = { { "Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false) },{ "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },{ "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },{ "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },    { "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };

JTable table = new JTable(data, columnNames);
TableCellRenderer myRenderer = new HeaderRenderer(table);
table.getTableHeader().setDefaultRenderer(myRenderer);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);

JScrollPane scrollPane = new JScrollPane(table);

add(scrollPane);
}

private static void createAndShowGUI() {
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

SimpleTableDemo newContentPane = new SimpleTableDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);

frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}