Search code examples
javaswinglayoutgridbaglayout

How to lock aspect ratio of a gridLayout in Java?


Is there an easy way of locking the aspect ratio of a GridLayout component in Java Swing ? Or should this be done on the JPanel containing that layout ?


Solution

  • GridLayout effectively ignores a component's preferred size, but you can control the aspect ratio of whatever is drawn in paintComponent(), as shown in this example. The rendered shape remains circular (1:1 aspect), while (nearly) filling the container in the narrowest dimension. Resize the frame to see the effect.

    Addendum: For example, I added N * N instances of CirclePanel to a GridLayout below.

    enter image description here

    import java.awt.*;
    import java.awt.event.*;
    import java.util.Random;
    import javax.swing.*;
    
    /**
     * @see https://stackoverflow.com/a/9858355/230513
     * @see https://stackoverflow.com/a/3538279/230513
     */
    public class SwingPaint {
    
        private static final int N = 4;
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.setLayout(new GridLayout(N, N));
                    for (int i = 0; i < N * N; i++) {
                        frame.add(new CirclePanel());
                    }
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        }
    
        private static class CirclePanel extends JPanel {
    
            private static final Random r = new Random();
    
            public CirclePanel() {
                this.setPreferredSize(new Dimension(80, 80));
                this.setForeground(new Color(r.nextInt()));
                this.addMouseListener(new MouseAdapter() {
    
                    @Override
                    public void mousePressed(MouseEvent e) {
                        CirclePanel.this.update();
                    }
                });
            }
    
            public void update() {
                this.setForeground(new Color(r.nextInt()));
            }
    
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                Dimension size = this.getSize();
                int d = Math.min(size.width, size.height) - 10;
                int x = (size.width - d) / 2;
                int y = (size.height - d) / 2;
                g.fillOval(x, y, d, d);
                g.setColor(Color.blue);
                g.drawOval(x, y, d, d);
            }
        }
    }