JTable多个标题行

我在我的应用程序中使用JTable并希望有2行标题,类似于: 喜欢这个

这甚至是可能还是我必须做别的事? 如果是这样,什么? 使用Supertitle-titleA,SuperTitle-titleB将占用太多空间并使信息冗余。

我们在上一个项目中有同样的要求。 我发现的是java2s.com上的GroupableTableHeader的实现。 然而,我有点拉皮条,虽然我不记得到底是什么。 下面是我们如何使用它们的三个类的实现。

ColumnGroup.java

import java.awt.Component; import java.awt.Dimension; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JTable; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; /** * ColumnGroup * * @version 1.0 20.10.1998 * @author Nobuo Tamemasa */ public class ColumnGroup { protected TableCellRenderer renderer; protected List columns; protected List groups; protected String text; protected int margin = 0; public ColumnGroup(String text) { this(text, null); } public ColumnGroup(String text, TableCellRenderer renderer) { this.text = text; this.renderer = renderer; this.columns = new ArrayList(); this.groups = new ArrayList(); } public void add(TableColumn column) { columns.add(column); } public void add(ColumnGroup group) { groups.add(group); } /** * @param column * TableColumn */ public List getColumnGroups(TableColumn column) { if (!contains(column)) { return Collections.emptyList(); } List result = new ArrayList(); result.add(this); if (columns.contains(column)) { return result; } for (ColumnGroup columnGroup : groups) { result.addAll(columnGroup.getColumnGroups(column)); } return result; } private boolean contains(TableColumn column) { if (columns.contains(column)) { return true; } for (ColumnGroup group : groups) { if (group.contains(column)) { return true; } } return false; } public TableCellRenderer getHeaderRenderer() { return renderer; } public void setHeaderRenderer(TableCellRenderer renderer) { this.renderer = renderer; } public String getHeaderValue() { return text; } public Dimension getSize(JTable table) { TableCellRenderer renderer = this.renderer; if (renderer == null) { renderer = table.getTableHeader().getDefaultRenderer(); } Component comp = renderer.getTableCellRendererComponent(table, getHeaderValue() == null || getHeaderValue().trim().isEmpty() ? " " : getHeaderValue(), false, false, -1, -1); int height = comp.getPreferredSize().height; int width = 0; for (ColumnGroup columnGroup : groups) { width += columnGroup.getSize(table).width; } for (TableColumn tableColumn : columns) { width += tableColumn.getWidth(); width += margin; } return new Dimension(width, height); } public void setColumnMargin(int margin) { this.margin = margin; for (ColumnGroup columnGroup : groups) { columnGroup.setColumnMargin(margin); } } } 

GroupableTableHeader.java

 import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; /** * GroupableTableHeader * * @version 1.0 20.10.1998 * @author Nobuo Tamemasa */ @SuppressWarnings("serial") public class GroupableTableHeader extends JTableHeader { @SuppressWarnings("unused") private static final String uiClassID = "GroupableTableHeaderUI"; protected List columnGroups = new ArrayList(); public GroupableTableHeader(TableColumnModel model) { super(model); setUI(new GroupableTableHeaderUI()); setReorderingAllowed(false); // setDefaultRenderer(new MultiLineHeaderRenderer()); } @Override public void updateUI() { setUI(new GroupableTableHeaderUI()); } @Override public void setReorderingAllowed(boolean b) { super.setReorderingAllowed(false); } public void addColumnGroup(ColumnGroup g) { columnGroups.add(g); } public List getColumnGroups(TableColumn col) { for (ColumnGroup group : columnGroups) { List groups = group.getColumnGroups(col); if (!groups.isEmpty()) { return groups; } } return Collections.emptyList(); } public void setColumnMargin() { int columnMargin = getColumnModel().getColumnMargin(); for (ColumnGroup group : columnGroups) { group.setColumnMargin(columnMargin); } } } 

GroupableTableHeaderUI.java

 import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; public class GroupableTableHeaderUI extends BasicTableHeaderUI { protected GroupableTableHeader getHeader() { return (GroupableTableHeader) header; } @Override public void paint(Graphics g, JComponent c) { Rectangle clipBounds = g.getClipBounds(); if (header.getColumnModel().getColumnCount() == 0) { return; } int column = 0; Dimension size = header.getSize(); Rectangle cellRect = new Rectangle(0, 0, size.width, size.height); Map groupSizeMap = new HashMap(); for (Enumeration enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) { cellRect.height = size.height; cellRect.y = 0; TableColumn aColumn = enumeration.nextElement(); List groups = getHeader().getColumnGroups(aColumn); int groupHeight = 0; for (ColumnGroup group : groups) { Rectangle groupRect = groupSizeMap.get(group); if (groupRect == null) { groupRect = new Rectangle(cellRect); Dimension d = group.getSize(header.getTable()); groupRect.width = d.width; groupRect.height = d.height; groupSizeMap.put(group, groupRect); } paintCell(g, groupRect, group); groupHeight += groupRect.height; cellRect.height = size.height - groupHeight; cellRect.y = groupHeight; } cellRect.width = aColumn.getWidth(); if (cellRect.intersects(clipBounds)) { paintCell(g, cellRect, column); } cellRect.x += cellRect.width; column++; } } private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) { TableColumn aColumn = header.getColumnModel().getColumn(columnIndex); TableCellRenderer renderer = aColumn.getHeaderRenderer(); if (renderer == null) { renderer = getHeader().getDefaultRenderer(); } Component c = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false, -1, columnIndex); c.setBackground(UIManager.getColor("control")); rendererPane.paintComponent(g, c, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); } private void paintCell(Graphics g, Rectangle cellRect, ColumnGroup cGroup) { TableCellRenderer renderer = cGroup.getHeaderRenderer(); if (renderer == null) { renderer = getHeader().getDefaultRenderer(); } Component component = renderer.getTableCellRendererComponent(header.getTable(), cGroup.getHeaderValue(), false, false, -1, -1); rendererPane .paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); } private int getHeaderHeight() { int headerHeight = 0; TableColumnModel columnModel = header.getColumnModel(); for (int column = 0; column < columnModel.getColumnCount(); column++) { TableColumn aColumn = columnModel.getColumn(column); TableCellRenderer renderer = aColumn.getHeaderRenderer(); if (renderer == null) { renderer = getHeader().getDefaultRenderer(); } Component comp = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false, -1, column); int cHeight = comp.getPreferredSize().height; List groups = getHeader().getColumnGroups(aColumn); for (ColumnGroup group : groups) { cHeight += group.getSize(header.getTable()).height; } headerHeight = Math.max(headerHeight, cHeight); } return headerHeight; } @Override public Dimension getPreferredSize(JComponent c) { int width = 0; for (Enumeration enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) { TableColumn aColumn = enumeration.nextElement(); width += aColumn.getPreferredWidth(); } return createHeaderSize(width); } private Dimension createHeaderSize(int width) { TableColumnModel columnModel = header.getColumnModel(); width += columnModel.getColumnMargin() * columnModel.getColumnCount(); if (width > Integer.MAX_VALUE) { width = Integer.MAX_VALUE; } return new Dimension(width, getHeaderHeight()); } } 

是的,您需要提供自己的JTableHeader 。 困难在于试图将其布局。

您需要查看JTableHeader.getHeaderRect(列) ,这将告诉渲染器如何布置列标题。

您将不得不考虑每个列渲染器的高度以及要使用标签渲染器的组件的高度(我建议使用Header的列渲染器作为基础,但这取决于您)

考虑列之间的空间(当多于两列连接到组时 – 组列的右边界变得不可见)。 这是解决方案:

  public Dimension getSize(JTable table) { Component comp = renderer.getTableCellRendererComponent( table, getHeaderValue(), false, false,-1, -1); int height = comp.getPreferredSize().height; int width = 0; Enumeration e = v.elements(); int testNum = 0; while (e.hasMoreElements()) { Object obj = e.nextElement(); if (obj instanceof TableColumn) { TableColumn aColumn = (TableColumn)obj; width += aColumn.getWidth()-table.getIntercellSpacing().width; width += margin; } else { width += ((ColumnGroup)obj).getSize(table).width-table.getIntercellSpacing().width; } } return new Dimension(width+2*table.getIntercellSpacing().width, height); }