【问题标题】:Java GridBagLayout JPanels automatically resizing issue?Java GridBagLayout JPanels 自动调整大小的问题?
【发布时间】:2015-03-15 21:25:40
【问题描述】:

我需要帮助调整红色 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();
        });
    }
}

【问题讨论】:

  • 对红色面板的要求发生了变化,需要占用更多空间,这是布局管理器的重点
  • 但是如果你看一下标签有这么多的可用空间,我设置标签的背景只是为了看看它需要多少空间,原始大小足以容纳标签,如果它不应该稍微变大,但在我的情况下,它只是大得离谱。

标签: java swing jpanel jlabel gridbaglayout


【解决方案1】:
//mainFrame.setLocation(screenDimension.width / 2 - mainFrame.getSize().width / 2, screenDimension.height / 2 - mainFrame.getSize().height / 2);
mainFrame.setLocationRelativeTo(null);

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

constructAppFrame();
constructTopMenuBar();

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

它只是愚蠢地开始使 RED JPanel 的尺寸变大,但它应该与 BLUE JPanel 的尺寸相同,应该保持 0.05 尺寸。

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

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

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

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

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

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

【讨论】:

  • 我最终没有使用网格袋布局 :) 实际上,我要求它们与我给它们的尺寸完全相同,以便为我将放置的其他组件留出足够的空间,而不是你的清晰解释。
猜你喜欢
  • 1970-01-01
  • 2015-07-21
  • 2014-02-20
  • 1970-01-01
  • 2017-03-22
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多