GridBagLayout布局如何实现窗口缩放时组件始终顶部对齐
问题描述
我在JFrame的内容面板中添加了五个按钮,原本期望组件从窗口最顶部开始排布,但调整窗口大小时,内容会向窗口中部偏移,请问如何才能让所有组件始终停靠在容器顶部?
以下是精简后的示例代码:
public class GridBagLayoutDemo { final static boolean shouldFill = true; final static boolean shouldWeightX = true; final static boolean RIGHT_TO_LEFT = false; public static void addComponentsToPane(Container pane) { if (RIGHT_TO_LEFT) { pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); } JButton button; pane.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); if (shouldFill) { //natural height, maximum width c.fill = GridBagConstraints.HORIZONTAL; } button = new JButton("Button 1"); if (shouldWeightX) { c.weightx = 0.5; } c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 0; pane.add(button, c); button = new JButton("Button 2"); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0.5; c.gridx = 1; c.gridy = 0; pane.add(button, c); button = new JButton("Button 3"); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0.5; c.gridx = 2; c.gridy = 0; pane.add(button, c); button = new JButton("Long-Named Button 4"); c.fill = GridBagConstraints.HORIZONTAL; //c.ipady = 40; //make this component tall c.weightx = 0.0; c.gridwidth = 3; c.gridx = 0; c.gridy = 1; pane.add(button, c); button = new JButton("5"); c.fill = GridBagConstraints.HORIZONTAL; //c.ipady = 40; //make this component tall c.weightx = 0.0; c.gridwidth = 3; c.gridx = 0; c.gridy = 2; pane.add(button, c); } private static void createAndShowGUI() { //Create and set up the window. JFrame frame = new JFrame("GridBagLayoutDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Set up the content pane. addComponentsToPane(frame.getContentPane()); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }
问题原因
GridBagLayout默认会将整个组件网格放在容器可用空间的居中位置。代码中所有组件都没有设置weighty(垂直权重)属性,默认值为0,意味着垂直方向的多余空间不会分配给任何一行,只能平均分布在组件网格的上下两侧,窗口拉高时组件自然会向中部偏移。
解决方案
修改成本最低的方式是调整最后一个按钮的约束配置,只需要加两行代码:
button = new JButton("5"); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0.0; // 新增以下两行 c.weighty = 1.0; c.anchor = GridBagConstraints.NORTH; c.gridwidth = 3; c.gridx = 0; c.gridy = 2; pane.add(button, c);
c.weighty = 1.0会让垂直方向所有多余空间全部分配给最后一行的单元格,其他行保持自身首选高度不变c.anchor = GridBagConstraints.NORTH会让最后一个按钮在自己占据的大单元格内靠顶部停靠,不会在单元格内垂直居中
更通用的扩展方案
如果后续需要在现有按钮下方继续添加其他组件,不建议把weighty设在最后一个业务组件上,可以在所有实际组件的最下方加一个透明占位组件吃掉多余垂直空间:
// 放在Button 5的添加逻辑之后 JLabel placeholder = new JLabel(); c.gridy = 3; c.weighty = 1.0; c.fill = GridBagConstraints.BOTH; pane.add(placeholder, c);
这种方式不会影响任何业务组件的布局逻辑,所有可见组件会始终停靠在容器顶部。
注意:
weighty的取值只看相对比例,上述例子中设为1和设为0.5的效果完全一致,只要是大于0的数就能拿到对应比例的多余空间。
内容的提问来源于stack exchange,提问作者Lek
相关产品推荐
相关产品推荐

