The quick and dirty way to solve this is to get rid of pack()
and subsitute revalidate()
and repaint
:
add(panel);
revalidate();
repaint();
// pack();
revalidate
tells the layout managers to re-lay out their components.repaint
requests that the component be repainted, especially "dirty" regionspack
tells the window to re-lay out all components and resize to the optimal size.
Much better would be to use a CardLayout, and the window and component size will remain constant, big enough to fit the largest component. ... and avoid all use of null layouts.
For example:
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Example2 extends JPanel {
public static final String[] COMBO_TEXTS = {"", "a", "b"};
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private DefaultComboBoxModel<String > comboModel = new DefaultComboBoxModel<>(COMBO_TEXTS);
private CardLayout cardLayout = new CardLayout();
public Example2() {
setLayout(cardLayout);
ComboListener comboListener = new ComboListener();
JComboBox<String> combo = new JComboBox<>(comboModel);
combo.addActionListener(comboListener);;
JPanel panelBlank = new JPanel();
panelBlank.add(combo);
JPanel panelWithText = new JPanel();
combo = new JComboBox<>(comboModel);
combo.addActionListener(comboListener);;
panelWithText = new JPanel();
panelWithText.add(combo);
panelWithText.add(new JLabel("Text"));
JPanel panelWithButton = new JPanel();
combo = new JComboBox<>(comboModel);
combo.addActionListener(comboListener);;
panelWithButton = new JPanel();
panelWithButton.add(combo);
panelWithButton.add(new JButton("Hello"));
add(panelBlank, COMBO_TEXTS[0]);
add(panelWithText, COMBO_TEXTS[1]);
add(panelWithButton, COMBO_TEXTS[2]);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class ComboListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JComboBox<String> combo = (JComboBox<String>)e.getSource();
String item = combo.getSelectedItem().toString();
cardLayout.show(Example2.this, item);
}
}
private static void createAndShowGui() {
Example2 mainPanel = new Example2();
JFrame frame = new JFrame("Example2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
This simplifies things and makes it harder to shoot yourself in the foot. So rather than this:
public void actionPerformed(ActionEvent e) {
value = (String) combo.getSelectedItem().toString();
if(value.equals("a")){
panel.add(a.getLabel());
panel.remove(b.getLabel());
// add(panel);
// pack();
}else if(value.equals("b")){
panel.add(b.getLabel());
panel.remove(a.getLabel());
// add(panel);
// pack();
}
add(panel);
revalidate();
repaint();
}
Your ActionListener's actionPerformed method is just this:
public void actionPerformed(ActionEvent e) {
JComboBox<String> combo = (JComboBox<String>)e.getSource();
String item = combo.getSelectedItem().toString();
cardLayout.show(Example2.this, item);
}
For more on the CardLayout, its uses and functionality, please check out the CardLayout Tutorial. But in a nutshell, it automates the process of swapping "views" in a GUI, making it much harder to shoot yourself in the foot.