Panel added to BorderLayout.CENTER does not occupy

2019-08-03 21:57发布

问题:

I am currently learning to program GUI in Java, and I have a problem where the CENTER component does not occupy the remaining space in the frame. From what I've read BorderLayout will grant components in north/south their preferred height and the stretch it out to the edges, and west/east will be the opposite. The center component will then get whatever space is left. What I am trying to do is to create a simple window with a panel in the north region, and a panel in the center region. I give each their own background color so I can easily see the space they are given. However, instead of getting a window with a yellow top bar and the remaining space being occupied by the magenta panel, I get this.

The top panel is just a regular JPanel, but the center panel is a class extending JPanel which overrides paintComponent and fills the panel with a color. If I hardcode in a bigger area in the fillRect() it will actually fill the window. So I suspect there's something wrong happening when I call getHeight() and getWidth in the method. It also might be worth mentioning that the dawPanel always will paint a perfect square, if I resize the window into a rectangle longer on the Y-aksis the gap will appear on the bottom instead.

So my question is, how can I get the component added to the Borderlayout.CENTER to occupy all remaining space in the frame.contentPane()?

package oblig1;
import java.awt.*;
import javax.swing.*;

public class Oblig1 
{
    JFrame frame;
    JPanel infoPanel;
    DrawingPanel drawPanel;

    public static void main(String[] args) 
    {
        Oblig1 game = new Oblig1();
    }

    public Oblig1()
    {
        frame = new JFrame("Parachute Game");
        frame.setSize(860, 640);
        infoPanel = new JPanel();
        drawPanel = new DrawingPanel();

        infoPanel.setBackground(Color.yellow);
        infoPanel.setPreferredSize(new Dimension(840, 20));
        infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));

        drawPanel.setPreferredSize(new Dimension(840, 620));

        frame.getContentPane().add(infoPanel, BorderLayout.NORTH);
        frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//      frame.setResizable(false);
        frame.setVisible(true);
    }

    //This class represents the panel that paints all animated parts of the game
    public class DrawingPanel extends JPanel
    {
        public DrawingPanel()
        {
            setDoubleBuffered(true);
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.MAGENTA);

            g2d.fillRect(0, 0, drawPanel.getHeight(), drawPanel.getWidth());
        }
    }
}

回答1:

issue came from two code lines (and one code line missed

  • infoPanel.setPreferredSize(new Dimension(840, 20));

    and

  • infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));


  • BoxLayout required Min, Max and PreferredSize, otherwise missed Dimensions collided with another PreferredSize, in this case (infoPanel.setPreferredSize(new Dimension(840, 20)); ) that is laid in JFrame that uses BorderLayout

  • remove infoPanel.setPreferredSize(new Dimension(840, 20));, or its widht must be less than PreferredSize used for JPanel

  • painting in Swing by default never returns PreferredSize correctly back to the container, you jave to override getPreferredSize, for BoxLayout min, max and preferred size

  • use JFrame.pack() instead of sizing for min,max and preferredSize directly to the JComponents or container, nor to setSize for JFrame

  • not true at all, to see my EDIT --> use another LayoutManager for JPanel to reduce funny issue with painting if is JFrame resized

  • your paintComponent missed important code line super.paintComponent(g);

e.g.

import java.awt.*;
import javax.swing.*;

public class Oblig1 {

    JFrame frame;
    JPanel infoPanel;
    DrawingPanel drawPanel;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Oblig1();
            }
        });
    }

    public Oblig1() {
        frame = new JFrame("Parachute Game");
        //frame.setSize(860, 640);
        infoPanel = new JPanel() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(20, 20);
            }
        };
        drawPanel = new DrawingPanel();

        infoPanel.setBackground(Color.yellow);
        //drawPanel.setPreferredSize(new Dimension(840, 20));
        infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));
        //drawPanel.setPreferredSize(new Dimension(840, 620));
        frame.getContentPane().add(infoPanel, BorderLayout.NORTH);
        frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//      frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);
    }

    //This class represents the panel that paints all animated parts of the game
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        public DrawingPanel() {
            setDoubleBuffered(true);
        }

        @Override
        public Dimension getMinimumSize() {
            return new Dimension(300, 300);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }

        @Override
        public Dimension getMaximumSize() {
            return new Dimension(300, 300);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.MAGENTA);
            //g2d.fillRect(0, 0, getHeight(), getWidth());
            g2d.fillRect(0, 0, getWidth(), getHeight());
        }
    }
}

EDIT

to my point, is simple wrong

  • use another LayoutManager for JPanel to reduce funny issue with painting if is JFrame resized

  • there are wrong, reversed parameters for Height and Width, wrong code line g2d.fillRect(0, 0, getHeight(), getWidth()); should be g2d.fillRect(0, 0, getWidth(), getHeight());