如何使用 GridBagLayout 防止组件抖动?

Posted

技术标签:

【中文标题】如何使用 GridBagLayout 防止组件抖动?【英文标题】:How do I prevent component shaking with GridBagLayout? 【发布时间】:2021-09-20 22:30:59 【问题描述】:

我有一个 GUI,其中四个组件通过 GridBagLayout 彼此相邻布置。当我向右调整窗口大小时,最左边的组件会抖动,当我向左调整大小时,最右边。

这是一个例子:

import javax.swing.*;
import java.awt.*;

public class GBLShakeTest extends JPanel 
    public static void main(String[] args) 
        JFrame frame = new JFrame("GBLShakeTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(500, 500));
        frame.add(new GBLShakeTest());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    

    public GBLShakeTest() 
        super(new GridBagLayout());
        add(new JTextArea("component 1"), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
        add(new JTextArea("component 2"), new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
        add(new JTextArea("component 3"), new GridBagConstraints(2, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
        add(new JTextArea("component 4"), new GridBagConstraints(3, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
    

它甚至发生在仅使用 JButton 的 GridBagLayout demo from oracle 上。向右调整大小很好,但是当您向左放大窗口时,右边的 Button 会抖动。 有谁知道如何解决这个问题?

【问题讨论】:

如果代码被赋予了一个有意义的、描述性的类名,比如TestGBLShake,它就不太可能与我的垃圾代码目录中的MyFrameTest 等其他类名发生冲突。布局可能一次为一个组件分配额外空间。更改班级名称,我会进一步调查。 它甚至发生在 oracle 的仅使用 JButton 的 GridBagLayout 演示中。 - 我还注意到使用直接添加到框架的单个 JButton 的问题。所以使用 BorderLayout。当我以中等速度向右调整大小时,我看到一个“黑色”区域,直到布局完成。当以中等速度向左调整大小时,我看到右侧边缘按钮的“重叠”图像。所以这似乎是一个 Swing 布局问题或平台问题。我使用 JDK 11 或 Windows 10。 这也发生在 Linux 上的 Java 16 中。我怀疑这是由于double 权重值的不精确造成的。如果只有第一个分量的权重 x 非零,则不存在“抖动”。 (抖动实际上是第一个组件的 x 坐标在 0 和 1 之间交替。) @camickr 我也注意到了这一点,但我认为这是一个值得单独提问的单独问题。 【参考方案1】:

这绝对是 GridBagLayout 中的一个错误。我找不到解决方法,至少不使用 GridBagLayout。

对于某些容器大小,GridBagLayout 似乎将第一个组件的 X 坐标从 0 更改为 1。如果只有第一个组件的 weightx 非零,则不会出现问题(这让我怀疑这是浮点 weightx 值不准确的问题,但我没有尝试深入研究 GridBagLayout 源来确认) .

另一种方法是使用SpringLayout。 SpringLayout 很难使用,但它可以做很多 GridBagLayout 可以做的事情,但需要一些工作。 (编写过使用 Motif 的 XmForm 小部件的代码的人会认识到对其他组件的附件的使用,尽管 SpringLayout 的工作方式并不完全相同。)

SpringLayout layout = new SpringLayout();
setLayout(layout);

add(new JTextArea("component 1"));
add(new JTextArea("component 2"));
add(new JTextArea("component 3"));
add(new JTextArea("component 4"));

Component previous = null;
for (Component c : getComponents()) 
    // Attach component to top and bottom of container.
    layout.putConstraint(
        SpringLayout.NORTH, c, 0, SpringLayout.NORTH, this);
    layout.putConstraint(
        SpringLayout.SOUTH, c, 0, SpringLayout.SOUTH, this);

    if (previous != null) 
        // Attach component's left (west) edge to previous component's
        // right(east) edge.
        layout.putConstraint(
            SpringLayout.WEST, c, 0, SpringLayout.EAST, previous);
    

    previous = c;


// Bind this container's right (east) edge to the right (east) edge
// of the rightmost child component.
Component lastComponent = getComponent(getComponentCount() - 1);
layout.putConstraint(
    SpringLayout.EAST, this, 0, SpringLayout.EAST, lastComponent);

【讨论】:

非常感谢您的回答,请原谅我花了这么长时间来检查这个问题。我怀疑是一个错误,因为即使使用如此简单的 GUI 也会发生这种情况。 SpringLayout 版本完美运行。

以上是关于如何使用 GridBagLayout 防止组件抖动?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 GridBagLayout 定位组件?

如何使用 GridBagLayout 在 JPanel 中对齐组件中心?

如何使组件跨越 GridBagLayout 中的多个单元格

使用GridBagLayout控制行列的高度和宽度

java gridbaglayout 一个组件变化会影响其它组件的大小,能不能做一个设置能让每个组件的大小和位置固定呢

GridBagLayout布局