GridBagLayout:元素在非常特定的面板高度收缩
GridBagLayout: Elements shrink at a very specific panel height
我正在使用 GridBagLayout 创建一个包含 4 个子面板的面板。 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。为什么会发生这种情况,如何补救,如果这是一种残暴的做法,您可以提供什么详细的替代方案?
GridBagLayout
当没有足够的空间将组件的大小至少调整到它们的首选大小时,会出现奇怪的行为。它不会优雅地降级。
看来您正在尝试绝对布局。 GridBagLayout
和其他通用 LayoutManger
(其他 X-Y 布局管理器)在这些情况下效果不佳。
坚持使用 GridBagLayout
通常最好在 JScrollPane
或至少 JPanel
中使用它,最小尺寸取自其首选尺寸。
当 GridBagLayout 无法容纳所有子组件的首选尺寸时,它会“放弃”并将每个子组件设置为其最小尺寸。因此,一种解决方案是将每个组件的最小尺寸设置为其首选尺寸。
但是,与其尝试从数学上解释屏幕上的每个像素,您还有更可靠的选择。
一个解决方案是只设置一个面板的大小,在任何特定维度上,所以另一个总是占据剩余的space。这样,您就永远不会“溢出”可用 space。 BorderLayout 非常适合这种情况,因为它的中心组件被拉伸以占用所有可用的 space 侧面组件不使用。
因此,对于洋红色和蓝色面板,您只需设置洋红色面板的高度:
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);
并且由于系统的 window 管理器报告给 windows 的边界是不可靠的,因此您避免进行任何显式数学运算而只是最大化 window:
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);
我正在使用 GridBagLayout 创建一个包含 4 个子面板的面板。 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。为什么会发生这种情况,如何补救,如果这是一种残暴的做法,您可以提供什么详细的替代方案?
GridBagLayout
当没有足够的空间将组件的大小至少调整到它们的首选大小时,会出现奇怪的行为。它不会优雅地降级。
看来您正在尝试绝对布局。 GridBagLayout
和其他通用 LayoutManger
(其他 X-Y 布局管理器)在这些情况下效果不佳。
坚持使用 GridBagLayout
通常最好在 JScrollPane
或至少 JPanel
中使用它,最小尺寸取自其首选尺寸。
当 GridBagLayout 无法容纳所有子组件的首选尺寸时,它会“放弃”并将每个子组件设置为其最小尺寸。因此,一种解决方案是将每个组件的最小尺寸设置为其首选尺寸。
但是,与其尝试从数学上解释屏幕上的每个像素,您还有更可靠的选择。
一个解决方案是只设置一个面板的大小,在任何特定维度上,所以另一个总是占据剩余的space。这样,您就永远不会“溢出”可用 space。 BorderLayout 非常适合这种情况,因为它的中心组件被拉伸以占用所有可用的 space 侧面组件不使用。
因此,对于洋红色和蓝色面板,您只需设置洋红色面板的高度:
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);
并且由于系统的 window 管理器报告给 windows 的边界是不可靠的,因此您避免进行任何显式数学运算而只是最大化 window:
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);