javaswingjpanelrepaintjcheckbox

Which of those different update methods should I call to make components appear after being added to a JPanel?


In this simple code if I click the button a few times a few JCheckBoxes will be added to the JPanel. However the display is not updated unless right after add("TEST") I call either revalidate() (just invalidate() won't work), or updateFrame(). Also, if I use revalidate(), the JCheckBoxes appear but the JPanel is not resized. I'm also aware of the repaint() method, but I'm not sure how to use it or those other methods.

What is the relationship between those component update methods so I can achieve the minimum I want (the JCheckBoxes to appear and the JPanel to be resized)?

How could I simplify the code?

public class UserInterface2 {

    private final JFrame frame;
    private JButton button;
    private JPanel panel;
    
    public UserInterface2() {
        
        frame = new JFrame("Test App");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.getContentPane().setLayout(new BorderLayout());
        
        createButton();
        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
        
        frame.getContentPane().add(button, BorderLayout.WEST);
        frame.getContentPane().add(panel, BorderLayout.CENTER);
    }
    
    private void updateFrame() {
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    private void createButton() {
        button = new JButton("Text");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                add("TEST");
                panel.revalidate();
                //updateFrame();
            }
        });
    }
    
    public void show() {
        updateFrame();
    }

    private void add(String text) {
        panel.add(new JCheckBox(text));
    }
    
    public static void main(String [] args) {
        SwingUtilities.invokeLater(() -> new UserInterface2().show());
    }
}

Solution

  • The JPanel will resize, but you're not seeing it because it is constrained by the JFrame that holds it, which can't resize without explicitly telling it to do so.

    Suggestions:

    1. Put the JPanel inside of a JScrollPane which will allow the JPanel to resize as components are added (and revalidate() is called) or
    2. Call pack() on the enclosing top-level window, here a JFrame, after adding components to the JPanel which will re-size the entire GUI.

    Also consider

    For example:

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.GridLayout;
    import java.awt.event.KeyEvent;
    import javax.swing.*;
    
    public class UserInterface3 {
        private JPanel mainPanel = new JPanel(new BorderLayout());
        private JPanel panel = new JPanel(new GridLayout(0, 1));
        
        public UserInterface3() {
            JPanel wrapperPanel = new JPanel(new BorderLayout());
            wrapperPanel.add(panel, BorderLayout.PAGE_START);       
            JScrollPane scrollPane = new JScrollPane(wrapperPanel);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            scrollPane.getViewport().setPreferredSize(new Dimension(300, 300));
            
            JButton addCheckBoxBtn = new JButton("Add CheckBox");
            addCheckBoxBtn.addActionListener(e -> addCheckBox());
            addCheckBoxBtn.setMnemonic(KeyEvent.VK_A);
            JPanel btnPanel = new JPanel();
            btnPanel.add(addCheckBoxBtn);       
            
            
            mainPanel.add(scrollPane);
            mainPanel.add(btnPanel, BorderLayout.PAGE_END);     
        }
        
        private void addCheckBox() {
            panel.add(new JCheckBox("Test"));
            mainPanel.revalidate();
        }
    
        public JPanel getMainPanel() {
            return mainPanel;
        }
        
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                JFrame frame = new JFrame("GUI");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                UserInterface3 ui3 = new UserInterface3();
                frame.add(ui3.getMainPanel());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            });
        }
    }