doLayout() only lays out the component it's called on, which in this case is a JScrollPane. So the viewport and the scrollbars get size, but not the table, which is a subcomponent of the viewport.
validate() calls
validateTree() which
does propagate the doLayout. But if you look at the source code for validate() it only does this if the component has a peer (that is, it's displayable). And validateTree() is a protected method, so it can't be called directly.
So in theory, you need to replicate the propagation of doLayout yourself. Perhaps like so,
private static void propagateDoLayout(Component c) {
synchronized (c.getTreeLock()) {
c.doLayout();
if (c instanceof Container) {
for (Component subComp : ((Container) c).getComponents()) {
propagateDoLayout(subComp);
}
}
}
}
Then in your SSCCE, you simply insert the following statement after you set the size,
public static BufferedImage takeScreenShot(JComponent srs) {
...
srs.setSize(dim);
propagateDoLayout(srs);
...
}
This works ... to a certain extent. The table part is painted correctly, but the column header is suspiciously missing. After digging around a little bit, I found out that the column header isn't added to the JScrollPane until the JTable gets a peer. Here's the source for addNotify() of the JTable class
public void addNotify() {
super.addNotify();
configureEnclosingScrollPane();
}
and the configureEnclosingScrollPane() method is what adds the column header. And of course ... it to is a protected method.
So a complete solution would be to override the method and give it public access. You then call it manually, just before you set the size and propagate the doLayout on the JScrollPane.
This of course means that there probably isn't a JComponent to Image method that will always work as intended without putting the JComponent in a packed frame (do to this very case). But you should be able to properly paint
most JComponents by setting the size and doing the layout propagation thingy.