5

I want to put objects coming out of a JTable, layered on top of it, so using a JLayeredPane seems natural. However, getting this to paint properly, do the headers properly etc is very hard. How do I do this so that:

  • The Row headers appear and match up when it scrolls
  • The column headers appear and match up when it scrolls
  • The table paints properly
  • resizing doesn't mess everything up

Note that because JDesktopPane extends JLayeredPane, the answers to this question also allow you to have a JTable (or any other component) behind a JDesktopPane.

Nick Fortescue
  • 43,045
  • 26
  • 106
  • 134
  • Why do you want such complicated nesting? – mre Jul 12 '11 at 11:49
  • I want cells in the JTable to be able to expand to show more information, and for those expansions to stay with the JTable as it scrolls. In the related questions, someone else wanted to be able to lock animations on top of the JTable. When googling other people wanted to use this technique to freeze columns, but that seemed a bit hacky to me, there might be a better way of doing that – Nick Fortescue Jul 12 '11 at 11:52
  • Just throwing in another use case for the topic: a table represents a week calendar, whereas events on the calendar are displayed through the JLayeredPane. – Denis Abakumov Jun 07 '23 at 14:49

1 Answers1

5

Similar but not identical questions which help: Java - Is it possible to put a JLayeredPane inside JScrollPane? and How to display animation in a JTable cell and Swing GUI design with JScrollPane and JLayeredPane.

To do this properly there are three separate issues to consider: Sizing, Headers and UI changes.

Sizing

To scroll and paint properly the JScrollPane needs to know the size and preferred size of the component inside it, in this case the JLayeredPane. But you want the size to be set by the table, as other Components will be floating on top of the table. In this case the easiest way is to make the JLayeredPane delegate size related properties to the JTable as follows.

final JTable table = new JTable();
JLayeredPane layers = new JLayeredPane() {
  @Override
  public Dimension getPreferredSize() {
    return table.getPreferredSize();
  }

  @Override
  public void setSize(int width, int height) {
    super.setSize(width, height);
    table.setSize(width, height);
  }

  @Override
  public void setSize(Dimension d) {
    super.setSize(d);
    table.setSize(d);
  }
};
// NB you must use new Integer() - the int version is a different method
layers.add(label, new Integer(JLayeredPane.PALETTE_LAYER), 0);
JScrollPane scrolling = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                        JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrolling.setViewportView(layers);

If you didn't want the JTable to be the thing which determines the size of the JLayeredPane then it needs to be determined in some other way, and so does the table's size. Both will need setPreferredSize() and setSize() called on them explicitly.

Headers

As the JTable is no longer the viewport, you'll need to link the headers yourself. The following code will work:

scrolling.setColumnHeaderView(table.getTableHeader());
scrolling.setRowHeaderView(rowHeader);

UI

Also note that JTable does some nasty code in `configureEnclosingScrollPane()` and `configureEnclosingScrollPaneUI()`. If you want to get UI style changes to work properly, then you'll have to override these methods, but I haven't worked out how to do this yet.

Code Sample

The complete code sample is available over on GitHub.

Denis Abakumov
  • 355
  • 3
  • 11
Nick Fortescue
  • 43,045
  • 26
  • 106
  • 134