GridBagLayout:元素以非常特定的面板高度缩小

时间:2019-06-10 20:01:00

标签: java jframe jpanel gridbaglayout

我正在使用GridBagLayout创建一个由4个子面板组成的面板。 4个子面板分别为品红色,蓝色,红色和青色,而主面板为绿色。目标是以一定方式布置这四个子面板,并且从理论上讲,绿色不应该显示。幸运的是,我有一个实际的例子,说明了我想要实现的目标:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

    public static void main(String[] args) {

        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int width = d.width;
        int height = 1046;


        JFrame frame = new JFrame("4.5 test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel masterPanel = new JPanel(new GridBagLayout());
        masterPanel.setBackground(Color.GREEN);

        GridBagConstraints c = new GridBagConstraints();
        c.weightx = 1.0;
        c.weighty = 1.0;

    // 1
        JPanel leftUpper = new JPanel();
        leftUpper.setBackground(Color.MAGENTA);
        leftUpper.setPreferredSize(new Dimension(width/3, height/7));
        c.gridx = 0;
        c.gridy = 0;
        c.anchor = GridBagConstraints.NORTH;
        masterPanel.add(leftUpper, c);


    // 2
        JPanel leftLower = new JPanel();
        leftLower.setBackground(Color.BLUE);
        leftLower.setPreferredSize(new Dimension(width/3, height - height/7));
        c.gridheight = 2;
        c.anchor = GridBagConstraints.SOUTH;
        masterPanel.add(leftLower, c);

    // 3
        JPanel rightUpper = new JPanel();
        rightUpper.setBackground(Color.RED);
        rightUpper.setPreferredSize(new Dimension(width - width/3, height - height/5));
        c.gridx = 1;
        c.gridheight = 1;
        masterPanel.add(rightUpper, c);


    // 4
        JPanel rightLower = new JPanel();
        rightLower.setBackground(Color.CYAN);
        rightLower.setPreferredSize(new Dimension(width - width/3, height/5));
        c.gridy = 1;
        masterPanel.add(rightLower, c);



        frame.add(masterPanel);
        frame.pack();
        frame.setVisible(true);
    }

}

运行时, this correct result.实际上,低于1046的每个高度都可以正常工作。

但是,时刻将第16行更改为:

int height = 1047;

所有人都下地狱,我们得到this instead.这同样适用于1047以上的每个高度。面板位于正确的位置,但尺寸不正确。请注意,与高度不同,更改宽度没有(意外)效果。

如果这种行为不是由这么小的(任意的)限制引起的,我不会对此感到惊讶。对于上下文,我使用的是1.8 Java RunTime环境。我的电脑屏幕分辨率为1920x1080。为什么会发生这种情况,请问如何补救?如果这是一种残酷的做法,您可以提供什么详细的替代方法?

2 个答案:

答案 0 :(得分:0)

当GridBagLayout无法容纳所有子组件的首选大小时,它会“放弃”并将每个子组件设置为其最小大小。因此,一种解决方案是将每个组件的最小尺寸设置为其首选尺寸。

但是,与其尝试在数学上不考虑屏幕上的每个像素,您还拥有更强大的选项。

一种解决方案是仅将一个面板的大小设置为任何特定尺寸,以便另一个面板始终占用剩余空间。这样,您将永远不会“溢出”可用空间。 BorderLayout非常适合此操作,因为它的中心组件被拉伸以占用侧面组件不使用的所有可用空间。

因此,对于洋红色和蓝色面板,只需设置洋红色面板的高度:

JPanel leftPanel = new JPanel(new BorderLayout());

// 1
    JPanel leftUpper = new JPanel();
    leftUpper.setBackground(Color.MAGENTA);
    leftUpper.setPreferredSize(new Dimension(1, height/7));
    leftPanel.add(leftUpper, BorderLayout.NORTH);

// 2
    JPanel leftLower = new JPanel();
    leftLower.setBackground(Color.BLUE);
    leftPanel.add(leftLower, BorderLayout.CENTER);

红色和青色的颜色类似:

JPanel rightPanel = new JPanel(new BorderLayout());

// 3
    JPanel rightUpper = new JPanel();
    rightUpper.setBackground(Color.RED);
    rightPanel.add(rightUpper, BorderLayout.CENTER);


// 4
    JPanel rightLower = new JPanel();
    rightLower.setBackground(Color.CYAN);
    rightLower.setPreferredSize(new Dimension(1, height/5));
    rightPanel.add(rightLower, BorderLayout.SOUTH);

然后您执行与这两个面板相似的操作,将它们放在一起:

    JPanel masterPanel = new JPanel(new BorderLayout());
    masterPanel.setBackground(Color.GREEN);

    leftPanel.setPreferredSize(new Dimension(width / 3,
        leftPanel.getPreferredSize().height));

    masterPanel.add(leftPanel, BorderLayout.WEST);
    masterPanel.add(rightPanel, BorderLayout.CENTER);

并且由于报告系统的窗口管理器赋予窗口的边界是不可靠的,因此您避免做任何显式的数学运算,而只是最大化窗口:

    frame.add(masterPanel);
    frame.pack();
    frame.setExtendedState(Frame.MAXIMIZED_BOTH);
    frame.setVisible(true);

如果您绝对需要维持面板之间的比例(例如magenta_height:blue_height :: 1:6),则可以使用SpringLayout来做到这一点,但是SpringLayout更复杂,通常不是值得的麻烦。它允许您指定大小范围,该大小范围可以是其他大小范围的倍数:

    SpringLayout layout = new SpringLayout();

    JPanel masterPanel = new JPanel(layout);
    masterPanel.setBackground(Color.GREEN);

// 1
    JPanel leftUpper = new JPanel();
    leftUpper.setBackground(Color.MAGENTA);
    masterPanel.add(leftUpper);

// 2
    JPanel leftLower = new JPanel();
    leftLower.setBackground(Color.BLUE);
    masterPanel.add(leftLower);

// 3
    JPanel rightUpper = new JPanel();
    rightUpper.setBackground(Color.RED);
    masterPanel.add(rightUpper);

// 4
    JPanel rightLower = new JPanel();
    rightLower.setBackground(Color.CYAN);
    masterPanel.add(rightLower);

    Spring leftUpperHeight = Spring.height(leftUpper);
    Spring leftLowerHeight = Spring.scale(leftUpperHeight, 6);

    Spring rightLowerHeight = Spring.scale(leftUpperHeight, 7 / 5f);

    Spring leftWidth = Spring.width(leftUpper);
    Spring rightWidth = Spring.scale(leftWidth, 3);

    layout.getConstraints(leftLower).setHeight(leftLowerHeight);
    layout.getConstraints(rightLower).setHeight(rightLowerHeight);

    layout.getConstraints(rightUpper).setWidth(rightWidth);
    layout.getConstraints(rightLower).setWidth(rightWidth);

    // Place leftLower beneath leftUpper.
    layout.putConstraint(
        SpringLayout.NORTH, leftLower, 0,
        SpringLayout.SOUTH, leftUpper);

    // Make leftLower's width match leftUpper's width.
    layout.putConstraint(
        SpringLayout.WEST, leftLower, 0,
        SpringLayout.WEST, leftUpper);
    layout.putConstraint(
        SpringLayout.EAST, leftLower, 0,
        SpringLayout.EAST, leftUpper);

    // Make container high enough to hold both leftLower and leftUpper.
    layout.putConstraint(
        SpringLayout.SOUTH, masterPanel, 0,
        SpringLayout.SOUTH, leftLower);

    // Place rightUpper and rightLower to the right of leftUpper.
    layout.putConstraint(
        SpringLayout.WEST, rightLower, 0,
        SpringLayout.EAST, leftUpper);
    layout.putConstraint(
        SpringLayout.WEST, rightUpper, 0,
        SpringLayout.WEST, rightLower);

    // Make container wide enough to accommodate rightUpper and rightLower.
    layout.putConstraint(
        SpringLayout.EAST, masterPanel, 0,
        SpringLayout.EAST, rightLower);

    // Align bottom of rightLower with bottom of leftLower.
    layout.putConstraint(
        SpringLayout.SOUTH, rightLower, 0,
        SpringLayout.SOUTH, leftLower);

    // Place rightUpper above rightLower.
    layout.putConstraint(
        SpringLayout.SOUTH, rightUpper, 0,
        SpringLayout.NORTH, rightLower);

    // Stretch rightUpper to reach to the top of the container.
    layout.putConstraint(
        SpringLayout.NORTH, rightUpper, 0,
        SpringLayout.NORTH, masterPanel);

答案 1 :(得分:-1)

GridBagLayout在没有足够的空间将组件调整为至少其首选大小时具有奇怪的行为。它不会优雅地降级。

似乎您正在尝试使用绝对布局。 GridBagLayout以及其他一般的LayoutManger(其他X-Y布局管理器)在这些情况下效果不佳。

GridBagLayout匹配时,通常最好在JScrollPane或至少JPanel内使用,且最小尺寸应取自其首选大小。