Java GridBagLayout JPanels 自动调整大小问题?

Java GridBagLayout JPanels automatically resizing issue?

我需要有关调整红色 JPanel 大小的帮助。基本上问题是我为 RED 和 BLUE JPanel 设置了相同大小的网格包约束并且它工作完美,直到我添加 JLabel,然后它只是愚蠢地开始使 RED JPanel 更大的尺寸,但它应该与以下尺寸相同BLUE JPanel,它应该保持在 0.05 大小。如果您能帮助我,我将不胜感激,在此先感谢您:)

package weatherapp;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

public class WeatherApp {

    JFrame mainFrame = new JFrame("Weather App");
    Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
    GridBagConstraints gbc = new GridBagConstraints();
    JPanel topMenuBar = new JPanel();
    JPanel weatherInfoMaster = new JPanel();
    JPanel weatherGraphMaster = new JPanel();
    JPanel bottomMenuBar = new JPanel();
    JLabel currentDateLabel = new JLabel(new SimpleDateFormat("dd MMMM yyyy").format(new Date()));

    WeatherApp() {
        constructAppFrame();
        constructTopMenuBar();
    }

    public void constructAppFrame() {
        mainFrame.setSize(540, 960);
        mainFrame.setPreferredSize(new Dimension(540, 960));
        //Terminate the program when the user closes the app.
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setResizable(false);
        mainFrame.setLocation(screenDimension.width / 2 - mainFrame.getSize().width / 2, screenDimension.height / 2 - mainFrame.getSize().height / 2);
        mainFrame.setLocationRelativeTo(null);
        mainFrame.setLayout(new GridBagLayout());

        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 1;
        gbc.weighty = 0.05;
        mainFrame.add(topMenuBar, gbc);
        gbc.gridy = 1;
        gbc.weighty = 0.6;
        mainFrame.add(weatherInfoMaster, gbc);
        gbc.gridy = 2;
        gbc.weighty = 0.5;
        mainFrame.add(weatherGraphMaster, gbc);
        gbc.gridy = 3;
        gbc.weighty = 0.05;
        mainFrame.add(bottomMenuBar, gbc);

        mainFrame.pack();
        mainFrame.setVisible(true);
    }

    public void constructTopMenuBar() {
        topMenuBar.setBackground(Color.RED);
        //topMenuBar.setBorder(new EmptyBorder(-20, 20, -20, 20));
        topMenuBar.setLayout(new BoxLayout(topMenuBar, BoxLayout.X_AXIS));
        currentDateLabel.setForeground(Color.WHITE);
        currentDateLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
        currentDateLabel.setBackground(Color.BLUE);
        currentDateLabel.setOpaque(true);

        topMenuBar.add(currentDateLabel);

        weatherInfoMaster.setBackground(Color.CYAN);
        weatherGraphMaster.setBackground(Color.GREEN);
        bottomMenuBar.setBackground(Color.BLUE);
    }

    public static void main(String[] args) {
        //Create the frame on the event dispacthing thread.
        SwingUtilities.invokeLater(() -> {
            new WeatherApp();
        });
    }
}
//mainFrame.setLocation(screenDimension.width / 2 - mainFrame.getSize().width / 2, screenDimension.height / 2 - mainFrame.getSize().height / 2);
mainFrame.setLocationRelativeTo(null);

不需要第一个语句,因为 setLocationRelativeTo(...) 将重置位置。

constructAppFrame();
constructTopMenuBar();

不要在框架可见后向框架添加组件。两个语句的顺序要颠倒

it just stupidly starts making the RED JPanel Larger size, but it should of been the same size as the BLUE JPanel, 0.05 size it should of stay at.

不傻。这是布局管理器定义明确的行为。每个布局管理器都有自己的规则要遵循。 GridBagLayout 适用于 "preferred size" 个组件。当没有组件添加到面板时,首选大小为 (10, 10),因为 JPanel 默认使用 FlowLayout,默认间隙 before/after 组件为 5 像素。

因此,当额外的 space 可用时,GridBagLayout 会根据首选大小分配 space,这会导致红色变得更多 space。

作为快速破解(在遵循我上面的其他建议之后),您可以:

bottomMenuBar.setPreferredSize( topMenuBar.getPreferredSize() );
mainFrame.add(bottomMenuBar, gbc);

现在尺寸将相同,因为首选尺寸也相同。这个概念证明并不是一个很好的解决方案,因为即使您更改红色面板,蓝色面板的首选尺寸也会固定。

也许更好的解决方案是使用 Relative Layout。此布局将根据框架中可用的 space 而非首选大小调整组件大小,因此如果 red/blue 面板具有相同的相对大小,即使添加了组件,它们的大小也应该相同。