I tried the solution of setting sizes above but it has many problems in my case because the state must be set in my application based on stored preference and the expanded size is thus not known on construction.
I found it is much simpler to just set the visibility of enclosed panels false and revalidate. Sample code below for this effect in my code:
static prefs=Preferences.node("myprefsnode"); // check, might be different for you
private class GroupPanel extends JPanel {
private TitledBorder border;
private Dimension collapsedSize;
private boolean collapsible = true, collapsed;
final String collapsedKey;
JPanel placeholderPanel = new JPanel();
Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR),
uncollapseCursor = new Cursor(Cursor.N_RESIZE_CURSOR),
collapseCursor = new Cursor(Cursor.S_RESIZE_CURSOR);
public GroupPanel(String title) {
setName(title);
collapsedKey = "GroupPanel." + getName() + "." + "collapsed";
border = new TitledBorder(getName());
border.setTitleColor(Color.black);
setToolTipText(String.format("Group %s (click title to collapse or expand)", title));
setAlignmentX(LEFT_ALIGNMENT);
setAlignmentY(TOP_ALIGNMENT);
// because TitledBorder has no access to the Label we fake the size data ;)
final JLabel l = new JLabel(title);
Dimension d = l.getPreferredSize(); // size of title text of TitledBorder
collapsedSize = new Dimension(getMaximumSize().width, d.height + 2); // l.getPreferredSize(); // size of title text of TitledBorder
collapsed = prefs.getBoolean(collapsedKey, false);
setTitle();
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
if (isMouseInHotArea(e)) {
if (collapsed) {
setCursor(uncollapseCursor);
} else {
setCursor(collapseCursor);
}
} else {
setCursor(normalCursor);
}
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (!collapsible) {
return;
}
if (getBorder() != null && getBorder().getBorderInsets(GroupPanel.this) != null) {
Insets i = getBorder().getBorderInsets(GroupPanel.this);
if (e.getX() " + getName());
}
setBorder(border);
}
public void setCollapsible(boolean collapsible) {
this.collapsible = collapsible;
}
public boolean isCollapsible() {
return this.collapsible;
}
public void setTitle(String title) {
border.setTitle(title);
}
/**
* @return the collapsed
*/
public boolean isCollapsed() {
return collapsed;
}
}