javaswingjbuttongrid-layoutboxlayout

Why is my JButton size not changing with either setSize() or setPreferredSize()?


I am making a basic calculator for a school project, and one of the requirements I need to meet is to change the size of a JButton inside of a JPanel. I have tried to do this, but it doesn't change.

I have tried to use both setSize() and setPreferredSize() to change it, but neither of those methods work. I have also tried to set its size without adding it to the JPanels (explained in the code) and just adding it to the frame and that doesn't work either.

For online help, I have looked at this question here on Stack Overflow, and I (somewhat) copied it's code but it doesn't work.

Can someone tell me what I am doing wrong?

Code

Imports

import java.awt.GridLayout ;
import java.awt.Dimension ;
import java.awt.event.ActionEvent ;
import java.awt.event.ActionListener ;
import javax.swing.JFrame ;
import javax.swing.JPanel ;
import javax.swing.JButton ;
import javax.swing.BoxLayout ;

Class

public class Main {
    public JFrame frame = new JFrame("Calculator") ;
    public JButton one = new JButton("1") ;
    public JPanel mainPanel = new JPanel() ;
    public JPanel buttonsPanel = new JPanel() ;
    public static void main(String[] args) {
        Main main = new Main() ;

        main.one.setPreferredSize(new Dimension(500, 500)) ;

        main.one.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Take that fat L") ;
            }
        }) ;


        main.buttonsPanel.setLayout(new GridLayout(5, 3)) ;
        main.buttonsPanel.setMaximumSize(new Dimension(2500, 1500)) ;
        main.buttonsPanel.add(main.one) ;
        main.mainPanel.setLayout(new BoxLayout(main.mainPanel, BoxLayout.Y_AXIS)) ;
        main.mainPanel.add(main.buttonsPanel) ;

        main.frame.setContentPane(main.mainPanel) ;
        main.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
        main.frame.setSize(500, 700) ;
        main.frame.setLocationRelativeTo(null) ;
        main.frame.setVisible(true) ;
    }
}

Solution

  • The combination of setPreferredSize, setMinimumSize and setSize (on the window) are working against you.

    I got rid of buttonsPanel.setMaximumSize(new Dimension(2500, 1500)); and replaced frame.setSize(500, 700) with frame.pack() and this seems to have fixed the immediate problem.

    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Main {
        public static void main(String[] args) {
            new Main();
        }
    
        public Main() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
            public JButton one = new JButton("1");
            public JPanel buttonsPanel = new JPanel();
    
            public TestPane() {
                one.setPreferredSize(new Dimension(500, 500));
    
                one.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("Take that fat L");
                    }
                });
    
                buttonsPanel.setLayout(new GridLayout(5, 3));
                //buttonsPanel.setMaximumSize(new Dimension(2500, 1500));
                buttonsPanel.add(one);
                setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
                add(buttonsPanel);
            }
        }
    }
    

    However, this leaves you with another problem. setPreferredSize is overriding the internal logic used by the button to calculate it's preferred size based on it's internal properties.

    This might not seem like a big issue, but when you have users with unusual font settings, it quickly comes back to haunt you.

    Swing has a good layout management system and you should spend some time trying to work out how to make use of it.

    For example, if we start with something like...

    public class TestPane extends JPanel {
        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.ipadx = 50;
            gbc.ipady = 50;
            int count = 0;
            for (int row = 0; row < 3; row++) {
                for (int col = 0; col < 3; col++) {
                    JButton btn = new JButton(Integer.toString(++count));
                    gbc.gridy = row;
                    gbc.gridx = col;
                    add(btn, gbc);
                }
            }
        }
    }
    

    Now, this is making use of GridBagLayout, not the simplest of layouts, but defiantly one of the most flexible. The reason for choosing it is it allows the possibility of applying an "internal" padding to the components, in this example, adding 50 to both the width and height.

    This will generate something like...

    enter image description here

    Okay, big deal you say. But consider what happens when the font size changes (in this example I manually modify the font size, but it could also come from system settings/preferences)

    public class TestPane extends JPanel {
        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.ipadx = 50;
            gbc.ipady = 50;
            int count = 0;
            Font font = new JButton().getFont();
            font = font.deriveFont(font.getSize2D() * 12);
            for (int row = 0; row < 3; row++) {
                for (int col = 0; col < 3; col++) {
                    JButton btn = new JButton(Integer.toString(++count));
                    btn.setFont(font);
                    gbc.gridy = row;
                    gbc.gridx = col;
    
                    add(btn, gbc);
                }
            }
        }
    }
    

    Which outputs something like...

    enter image description here

    And, without any modification to the original code (other then adding in the font sizing), the code just works.

    This is why we generally discourage the use of setPreferred/Minimum/MaximumSize

    Now, if you "really" want square buttons, I recommend having a look at Creating Square Buttons in Swing. You could also try something like this, but to be honestly, I prefer the first approach.