我正在使用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。为什么会发生这种情况,请问如何补救?如果这是一种残酷的做法,您可以提供什么详细的替代方法?
答案 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
内使用,且最小尺寸应取自其首选大小。