javaswingjpanellayout-managerboxlayout

Resizing of multiple JPanels to fit window


I'm pretty new to the Java Swing toolkit and have created a series of JPanel with JLabel components corresponding to each panel's index and value. However I can’t seem to make the panels correctly resize, when the window is too small to resize all the panels at once. Resulting in the an extra red margin to the right of all the panels (See. Window).

Is there a way to make the Sub Panels/Spacer Panels resize in such a way that does not allow for the extra margin? Or setup a better swing layout to handle such resizing?

Code demo:

import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import javax.swing.BoxLayout;

public class Frame extends JFrame {
    private int numBox = 20;

    public class SubPanel extends JPanel {
        public SubPanel(int i) {
            setMinimumSize(new Dimension(20, 20));
            setMaximumSize(new Dimension(1000, i*30));
            setBackground(Color.BLACK);
            setLayout(new BorderLayout());
            setAlignmentY(Component.BOTTOM_ALIGNMENT);

            JLabel labelValue = new JLabel(String.valueOf(30 * i), JLabel.CENTER);
            labelValue.setForeground(Color.WHITE);
            add(labelValue, BorderLayout.NORTH);

            JLabel labelIndex = new JLabel(String.valueOf(i), JLabel.CENTER);
            labelIndex.setForeground(Color.WHITE);
            add(labelIndex, BorderLayout.SOUTH);
        }
    }

    public class SpacerPanel extends JPanel {
        public SpacerPanel() {
            setBackground(Color.WHITE);
            setMaximumSize(new Dimension(3, 10000));
            setMinimumSize(new Dimension(3, 0));
        }
    }

    public Frame(String title) {
        super(title);

        JPanel mainPanel = new JPanel();
        mainPanel.setBackground(Color.RED);
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));

        for (int i = 1; i < numBox + 1; i++) {
            mainPanel.add(new SpacerPanel());
            mainPanel.add(new SubPanel(i));
        }
        mainPanel.add(new SpacerPanel());

        add(mainPanel);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        new Frame("Frame").setSize(1200, 700);
    }
}

Solution

  • If you have 40 components and you resize the frame by a few pixels, the BoxLayout is having problems allocating those pixels to each of the components.

    Instead you can use the Relative Layout which allows you to specify how those pixels should be allocated.

    The RelativeLayout also allows you to specify a gap between each component so you don't need to add the SpacerPanel.

    However, you will need to modify the logic of the "subPanel". The height of the labels needs to be fixed so they can be painted black. So I created a "labelPanel" to hold the labels.

    The restructured code using the RelativeLayout would be:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    import javax.swing.BoxLayout;
    
    public class Frame extends JFrame {
        private int numBox = 20;
    
        public class SubPanel extends JPanel {
            public SubPanel(int i) {
    //            setMinimumSize(new Dimension(20, 20));
    //            setMaximumSize(new Dimension(1000, i*30));
    //            setPreferredSize(new Dimension(20, i*30));
                setBackground(Color.RED);
                setLayout(new BorderLayout());
    //            setAlignmentY(Component.BOTTOM_ALIGNMENT);
    
                JPanel labelPanel = new JPanel( new BorderLayout() );
                labelPanel.setBackground( Color.BLACK );
                labelPanel.setPreferredSize(new Dimension(20, i*30));
                add(labelPanel, BorderLayout.PAGE_END);
    
                JLabel labelValue = new JLabel(String.valueOf(30 * i), JLabel.CENTER);
                labelValue.setForeground(Color.WHITE);
                labelPanel.add(labelValue, BorderLayout.NORTH);
    
                JLabel labelIndex = new JLabel(String.valueOf(i), JLabel.CENTER);
                labelIndex.setForeground(Color.WHITE);
                labelPanel.add(labelIndex, BorderLayout.SOUTH);
            }
        }
    
        public class SpacerPanel extends JPanel {
            public SpacerPanel() {
                setBackground(Color.WHITE);
                setMaximumSize(new Dimension(3, 10000));
                setMinimumSize(new Dimension(3, 0));
            }
        }
    
        public Frame(String title) {
            super(title);
    
            JPanel mainPanel = new JPanel();
    //        mainPanel.setBackground(Color.RED);
            mainPanel.setBackground(Color.WHITE);
    
    //        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
            RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 5);
            rl.setFill( true );
            rl.setRoundingPolicy(RelativeLayout.EQUAL);
            rl.setAlignment(RelativeLayout.TRAILING);
            mainPanel.setLayout( rl );
            Float constraint = new Float(1);
    
            for (int i = 1; i < numBox + 1; i++) {
    //            mainPanel.add(new SpacerPanel());
    //            mainPanel.add(new SubPanel(i));
                mainPanel.add(new SubPanel(i), constraint);
            }
    //        mainPanel.add(new SpacerPanel());
    
            add(mainPanel);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
        }
    
        public static void main(String[] args) {
            new Frame("Frame").setSize(1200, 700);
        }
    }
    

    Or this approach is closer to your original posting. It still uses the spacer and the height of the black columns will shrink as the frame height is decreased:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    import javax.swing.BoxLayout;
    
    public class Frame2 extends JFrame {
        private int numBox = 20;
    
        public class SubPanel extends JPanel {
            public SubPanel(int i) {
    //            setMinimumSize(new Dimension(20, 20));
    //            setMaximumSize(new Dimension(1000, i*30));
    //            setBackground(Color.BLACK);
                setBackground(Color.RED);
    //            setLayout(new BorderLayout());
                setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
                add(Box.createVerticalGlue());
    //            setAlignmentY(Component.BOTTOM_ALIGNMENT);
    
                JPanel labelPanel = new JPanel();
                labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
                labelPanel.setBackground( Color.BLACK );
                labelPanel.setPreferredSize(new Dimension(50, i*30));
                labelPanel.setMaximumSize(new Dimension(1000, labelPanel.getPreferredSize().height));
                add(labelPanel, BorderLayout.CENTER);
    
                JLabel labelValue = new JLabel(String.valueOf(30 * i), JLabel.CENTER);
                labelValue.setForeground(Color.WHITE);
                labelValue.setAlignmentX(JLabel.CENTER_ALIGNMENT);
    //            add(labelValue, BorderLayout.NORTH);
                labelPanel.add(labelValue);
    
                labelPanel.add(Box.createVerticalGlue());
    
                JLabel labelIndex = new JLabel(String.valueOf(i), JLabel.CENTER);
                labelIndex.setForeground(Color.WHITE);
                labelIndex.setAlignmentX(JLabel.CENTER_ALIGNMENT);
    //            add(labelIndex, BorderLayout.SOUTH);
                labelPanel.add(labelIndex);
            }
        }
    
        public class SpacerPanel extends JPanel {
            public SpacerPanel() {
                setBackground(Color.WHITE);
                setMaximumSize(new Dimension(3, 10000));
                setMinimumSize(new Dimension(3, 0));
            }
        }
    
        public Frame2(String title) {
            super(title);
    
            JPanel mainPanel = new JPanel();
            mainPanel.setBackground(Color.RED);
    //        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
            RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 0);
            rl.setFill( true );
            rl.setRoundingPolicy(RelativeLayout.EQUAL);
            rl.setAlignment(RelativeLayout.TRAILING);
            mainPanel.setLayout( rl );
            Float constraint = new Float(1);
    
            for (int i = 1; i < numBox + 1; i++) {
                mainPanel.add(new SpacerPanel());
    //            mainPanel.add(new SubPanel(i));
                mainPanel.add(new SubPanel(i), constraint);
            }
            mainPanel.add(new SpacerPanel());
    
            add(mainPanel);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
        }
    
        public static void main(String[] args) {
            new Frame2("Frame").setSize(1200, 700);
        }
    }