I’m creating an (j)applet where the user has access to several different views selectable from a tree. The applet has a main area where the current view is displayed inside a scrollpane, replacing whatever was previously there. Most of the time this works fine, but when the view to be replaced has a more complicated layout, as in large (~100 components), not nested, the removal takes several seconds! Creation of the large view is lightning quick, only the removal is slow. This is only noticeable in applets, running the application in a JFrame is still as fast as I expect. I use GridBagLayout for the view.
After some experimentation, I found that if I replace
contents.remove(view); //contents is the view of the scrollpane.
with
view.removeAll();
contents.remove(view);
then the whole process is very fast.
My guess is that the cause of this behavior is some of Java’s layout “magic”, and although I have a solution it doesn’t feel right and seems to indicate that I don’t fully understand what’s going on. So my question(s) is this:
Does someone know what’s actually happening? Is there a better (clearer) way to accomplish the same thing?
Edit: SSCCE: http://pastebin.com/VC1T7zGv
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SSCCE extends JApplet {
private boolean state;
public void init() {
super.init();
getContentPane().add(setupSwitchPanel(), BorderLayout.NORTH);
getContentPane().add(setupSimplePanel(), BorderLayout.CENTER);
}
private JPanel setupSwitchPanel() {
JPanel switchPanel = new JPanel();
switchPanel.add(new JButton(new AbstractAction("Switch panels (slow)") {
@Override
public void actionPerformed(ActionEvent arg0) {
switchComponents();
}
}));
switchPanel.add(new JButton(new AbstractAction("Switch panels (fast)") {
@Override
public void actionPerformed(ActionEvent arg0) {
((JPanel)getContentPane().getComponent(1)).removeAll();
switchComponents();
}
}));
return switchPanel;
}
private void switchComponents() {
getContentPane().remove(1);
if (state)
getContentPane().add(setupSimplePanel(), BorderLayout.CENTER);
else
getContentPane().add(setupComplexPanel(), BorderLayout.CENTER);
state = !state;
getContentPane().validate();
}
private JPanel setupComplexPanel() {
JPanel contents = new JPanel();
contents.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
for (int x = 0; x<10; x++) {
c.gridx = x;
for (int y = 0; y<10; y++) {
c.gridy = y;
contents.add(new JLabel(x + ", " + y), c);
}
}
return contents;
}
private JPanel setupSimplePanel() {
JPanel contents = new JPanel();
contents.add(new JLabel("Simple view"));
return contents;
}
}
Alternate strategy: Use a
CardLayout.Why? The typical memory could allow the storage of hundreds of cards with hundreds of components.
Create them lazily and the GUI might only have 20-40 cards in a typical usage run. Of course, re-use existing cards for common tasks, just change the content.