Java 嵌套的 JPanel 未保持指定的大小

Java nested JPanel is not maintaining the specified size

我有一个 JFrame,其中包含 2 个 JPanels,其中一个是 JFrame 的 70%,另一个是剩余的 30%。 JPanel 是宽度的 30%,其中有一个嵌套的 JPanel。然而,这个嵌套的 JPanel 应该是其父级 JPanel 宽度的 50%,但是当它显示时,它占据了父级 JPanel.

的整个宽度

父级 JPanel 属于 width 358height 772,嵌套的 JPanel 具有以下值:width 179height 772

我已将这些组件的颜色设置为绿色和灰色,因此我可以轻松查看它们是否正确呈现。当我 运行 我的应用程序时,嵌套的 JPanel 实际上被呈现为好像它是 parent 的整个宽度(整个区域呈现绿色)。

这是当前的代码。

public class DisplayFrame extends JFrame{

    private final static int WIDTH = 1200;
    private final static int HEIGHT = 800;      
    private DisplayCanvas canvas;   
    private ControlContainer controlContainer;

    public DisplayFrame() {    
        //simple inheritance. 
        super(title);
        setSize(new Dimension(WIDTH, HEIGHT));
        setResizable(false);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);    
        addComponents(this.getContentPane());    
    } 

    public void addComponents(Container container){
        canvas = DisplayCanvas.getInstance(container);    
        canvas.setAlignmentX(Component.LEFT_ALIGNMENT);
        container.add(canvas);          
        controlContainer = ControlContainer.getInstance(container);    
        controlContainer.setAlignmentX(Component.RIGHT_ALIGNMENT);
        container.add(controlContainer);
    }    
}

70%宽度的面板

public class DisplayCanvas extends JPanel{

    private final double WIDTH_PERCENT = 70;    
    private static DisplayCanvas instance;

    private DisplayCanvas(Container parent) {    
        this.setSize(new Dimension(MathHelper.calculateXPercentOfY(WIDTH_PERCENT, 
            parent.getWidth()), parent.getHeight()));
        this.setBackground(Color.WHITE);
        this.setVisible(true);    
    }
    //implement the singleton 
    public static DisplayCanvas getInstance(Container parent) {    
        if(instance != null){
            return instance;
        }    
        instance = new DisplayCanvas(parent);    
        return instance;
    }
}

面板宽度为 30%:

public class ControlContainer extends JPanel{

    private final double WIDTH_PERCENT = 30;
    private static ControlContainer instance;
    private ControlPanel controlPanel;

    private ControlContainer(Container parent) {
        this.setSize(new Dimension(MathHelper.calculateXPercentOfY(WIDTH_PERCENT, 
             parent.getWidth()), parent.getHeight()));
        this.setBackground(Color.GRAY);
        this.setLayout(new BorderLayout(0,0));
        this.setVisible(true);
        addControlElements(this);           
    }

    //implement Singelton
    public static ControlContainer getInstance(Container parent){    
        if(instance != null){
            return instance;
        }    
        instance = new ControlContainer(parent);        
        return instance;    
    }

    public void addControlElements(Container parent){           
        controlPanel = ControlPanel.getInstance(parent);
        controlPanel.setAlignmentX(LEFT_ALIGNMENT);         
        System.out.println("ControlContainer: " + parent.getWidth() 
             + "       " + parent.getHeight()+ " vis: " + parent.isVisible());
        System.out.println("ControlPanel: " + controlPanel.getWidth() 
             + "       " + controlPanel.getHeight() + " vis: " + controlPanel.isVisible());
        parent.add(controlPanel, BorderLayout.CENTER);                  
    }
}

现在,此面板应嵌套在 ControlContainer 内,占其宽度的 50%。

public class ControlPanel extends JPanel{       

        private final double WIDTH_PERCENT = 50;        
        private static ControlPanel instance;

        private ControlPanel(Container parent) {
            super.setSize(new Dimension(MathHelper.calculateXPercentOfY(WIDTH_PERCENT, 
                  parent.getWidth()), parent.getHeight()));
            super.setBackground(Color.GREEN);
            super.setVisible(true);        
        }

        //implement singelton measures
        public static ControlPanel getInstance(Container parent){        
            if(instance != null){
                return instance;
            }        
            instance = new ControlPanel(parent);        
            return instance;        
        }
    }

这是 addControlElements 方法的输出:

ControlContainer: 358       772 vis: true
ControlPanel: 179       772 vis: true

这只是用来测试值是否按预期设置,如您所见 ControlPanel width is 179 然而,这是预期的,当呈现时它会填充整个 ControlContainer.

希望你明白我的意思,这不是最容易解释的。

首先查看 Laying Out Components Within a Container to understand how components are laied out in Swing. Take a look at How to Use GridBagLayout 以了解如何实现您正在寻找的结果

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new BasePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BasePane extends JPanel {

        public BasePane() {
            TestPane top = new TestPane();
            TestPane bottom = new TestPane();

//          top.setBorder(new LineBorder(Color.RED));
//          bottom.setBorder(new LineBorder(Color.BLUE));

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.weightx = 1;
            gbc.weighty = 0.3;

            add(top, gbc);

            gbc.gridy++;
            gbc.weighty = 0.7;

            add(bottom, gbc);
        }

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


    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            Dimension mySize = getSize();
            Dimension parentSize = getParent().getSize();

            String widthPer = NumberFormat.getPercentInstance().format((float) mySize.width / (float) parentSize.width);
            String heightPer = NumberFormat.getPercentInstance().format((float) mySize.height / (float) parentSize.height);

            String[] text = new String[]{
                "Me = " + mySize.width + "x" + mySize.height,
                "Parent = " + parentSize.height + "x" + parentSize.height,
                "Perctange = " + widthPer + "x" + heightPer
            };

            FontMetrics fm = g2d.getFontMetrics();
            int y = (getHeight() - (fm.getHeight() * text.length)) / 2;
            for (String value : text) {
                int x = (getWidth() - fm.stringWidth(value)) / 2;
                g2d.drawString(value, x, y + fm.getAscent());
                y += fm.getHeight();
            }

            g2d.dispose();
        }

    }

}