java - 如何在盒子布局中使用VerticalGlue

标签 java swing layout-manager boxlayout

我正在尝试构建一个简单的面板,我将在其中添加一些字段并捕获一些用户数据。我通常使用 GridBagLayout(感谢垃圾神)和 BoxLayout 的组合来实现我想要的布局。我通常使用它们不会有任何问题,99% 的情况下它们只是做直观的事情,但我似乎无法使这个相当简单的面板正常工作。谁能告诉我为什么?

面板类:

import java.awt.Color;
import java.awt.Dimension;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class EmailPanel extends JPanel {
    private JButton m_OkButton;
    private JPanel m_MainPanel;

    private JTextField m_ServerIPTF;
    private JTextField m_ServerPortTF;
    private JTextField m_DomainNameTF;
    private JTextField m_UnitNameTF;

    private JTextField m_Recipient1TF;
    private JTextField m_Recipient2TF;

    private final Dimension LARGE_TEXTFIELD_SIZE = new Dimension(125, 25);
    public EmailPanel() {
        init();
    }

    private void init() {
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel tPanel;
        JLabel tLabel;

        Header: {
            tPanel = new JPanel();
            tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
            tPanel.add(Box.createHorizontalGlue());
            tLabel = new JLabel("Email Settings");
            tPanel.add(tLabel);
            tPanel.add(Box.createHorizontalGlue());
            tPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, Color.red));
            this.add(tPanel);
        }

        MainPanel: {
            m_MainPanel = new JPanel();
            m_MainPanel.setLayout(new BoxLayout(m_MainPanel, BoxLayout.Y_AXIS));
            m_MainPanel.add(Box.createVerticalStrut(5));
            tPanel = new JPanel();
            tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
            tPanel.add(Box.createHorizontalStrut(3));
            tLabel = new JLabel("Server IP Address:");
            tPanel.add(tLabel);
            tPanel.add(Box.createHorizontalStrut(3));
            m_ServerIPTF = new JTextField();
            m_ServerIPTF.setMinimumSize(LARGE_TEXTFIELD_SIZE);
            m_ServerIPTF.setMaximumSize(LARGE_TEXTFIELD_SIZE);
            m_ServerIPTF.setPreferredSize(LARGE_TEXTFIELD_SIZE);
            tPanel.add(m_ServerIPTF);
            tPanel.add(Box.createHorizontalStrut(25));
            tLabel = new JLabel("Server Port");
            tPanel.add(tLabel);
            tPanel.add(Box.createHorizontalStrut(3));
            m_ServerPortTF = new JTextField();
            m_ServerPortTF.setMinimumSize(LARGE_TEXTFIELD_SIZE);
            m_ServerPortTF.setMaximumSize(LARGE_TEXTFIELD_SIZE);
            m_ServerPortTF.setPreferredSize(LARGE_TEXTFIELD_SIZE);
            tPanel.add(m_ServerPortTF);
            tPanel.add(Box.createHorizontalGlue());
            m_MainPanel.add(tPanel);
            m_MainPanel.add(Box.createVerticalStrut(5));

            tPanel = new JPanel();
            tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
            tPanel.add(Box.createHorizontalStrut(6));
            tLabel = new JLabel("Domain Name:");
            tPanel.add(tLabel);
            tPanel.add(Box.createHorizontalStrut(3));
            m_DomainNameTF = new JTextField();
            m_DomainNameTF.setMinimumSize(LARGE_TEXTFIELD_SIZE);
            m_DomainNameTF.setMaximumSize(LARGE_TEXTFIELD_SIZE);
            m_DomainNameTF.setPreferredSize(LARGE_TEXTFIELD_SIZE);
            tPanel.add(m_DomainNameTF);
            tPanel.add(Box.createHorizontalGlue());
            m_MainPanel.add(tPanel);

            this.add(m_MainPanel);
        }

        OKButton: {
            m_OkButton = new JButton("Ok");
            tPanel = new JPanel();
            tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
            tPanel.add(Box.createHorizontalGlue());
            tPanel.add(m_OkButton);
            tPanel.add(Box.createHorizontalGlue());
            this.add(tPanel);
        }

        this.add(Box.createVerticalGlue());
    }
}

如果将其添加到/将其用作内容 Pane ,您将看到各个控件之间的 Y 轴上有很大的间隙。我的印象是,我在 init 方法末尾添加的垂直粘合应该会增长以占用 OK 按钮下方的所有空间,并且控件将结果被推到一起。我看到的是,它似乎在我的临时 JPanel 对象 tPanel 的各个实例和底部的垂直粘合之间均匀地分割了空间。我怎样才能让它停止这样做?

编辑:看起来,无论有没有多余的 m_MainPanel 对象,行为都是相同的。

这就是我在渲染时看到的情况,并且表单变得比控件所需的更大。我希望垂直粘合填充“确定”按钮下方的空间,以将控件保持在表单顶部。

enter image description here

最佳答案

我复制粘贴了您的代码并添加了 main 方法:

public static void main(String[] args) {

    JFrame frame = new JFrame();
    frame.getContentPane().add(new EmailPanel());
    frame.pack();
    frame.setVisible(true);
}

这是结果:

enter image description here

有或没有this.add(Box.createVerticalGlue());

这是你想要的还是不想要的?


编辑:解决方案

我编辑了您的代码以达到所需的结果:

public class EmailPanel extends JPanel {

    private JButton okButton;
    private JTextField serverIPTF;
    private JTextField serverPortTF;
    private JTextField domainNameTF;

    public static void main(String[] args) {

        JFrame frame = new JFrame();
        frame.getContentPane().add(new EmailPanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setMinimumSize(frame.getPreferredSize());
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public EmailPanel() {

        init();
    }

    private void init() {

        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel tPanel;
        JLabel tLabel;

// Header
        tLabel = new JLabel("Email Settings", JLabel.CENTER);
        tLabel.setAlignmentX(CENTER_ALIGNMENT);
        tLabel.setMaximumSize(new Dimension(Integer.MAX_VALUE, tLabel.getPreferredSize().height));
        tLabel.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, Color.red));
        add(tLabel);

// Fields
        JPanel fieldsPanel = new JPanel();
        fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.Y_AXIS));
        fieldsPanel.setBorder(BorderFactory.createMatteBorder(5, 3, 5, 3, new Color(0, 0, 255, 255)));

// Top fields
        serverIPTF = new JTextField(10);
        serverIPTF.setMaximumSize(serverIPTF.getPreferredSize());
        serverPortTF = new JTextField(10);
        serverPortTF.setMaximumSize(serverPortTF.getPreferredSize());

        tPanel = new JPanel();
        tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));

        tPanel.add(new JLabel("Server IP Address:"));
        tPanel.add(Box.createRigidArea(new Dimension(3, 0)));
        tPanel.add(serverIPTF);
        tPanel.add(Box.createRigidArea(new Dimension(25, 0)));
        tPanel.add(new JLabel("Server Port"));
        tPanel.add(Box.createRigidArea(new Dimension(3, 0)));
        tPanel.add(serverPortTF);
        tPanel.add(Box.createHorizontalGlue());
        fieldsPanel.add(tPanel);

        fieldsPanel.add(Box.createRigidArea(new Dimension(0, 5)));

// Lower field
        domainNameTF = new JTextField(10);
        domainNameTF.setMaximumSize(domainNameTF.getPreferredSize());

        tPanel = new JPanel();
        tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));

        tPanel.add(new JLabel("Domain Name:"));
        tPanel.add(Box.createRigidArea(new Dimension(3, 0)));
        tPanel.add(domainNameTF);
        tPanel.add(Box.createHorizontalGlue());
        fieldsPanel.add(tPanel);

        add(fieldsPanel);

// OK Button
        okButton = new JButton("OK");
        okButton.setAlignmentX(CENTER_ALIGNMENT);
        add(okButton);
    }
}

说明:

BoxLayout说:

When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the vertical space of the layout does not match the sum of the preferred heights, then BoxLayout tries to resize the components to fill the space. The components either grow or shrink to fill the space, with BoxLayout honoring the minimum and maximum sizes of each of the components. Any extra space appears at the bottom of the container.

(强调我的)

这告诉我们,如果我们将组件的最大高度限制为其首选高度,则所有额外的垂直空间都将到达底部,正如您所希望的那样。因此,我们为所有文本字段添加了以下行(标签不垂直增长):

nameTF.setMaximumSize(nameTF.getPreferredSize());

我们不需要任何垂直胶水。

注释:

  • 我创建了 10 列的文本字段,您可以更改此值。
  • 顶部标签不需要水平粘合来拉伸(stretch)它,只需放宽最大宽度约束并设置对齐方式(与底部按钮类似)。
  • 我没有创建大量刚性区域(您使用了支柱),而是创建了一个具有适当宽度的边框。出于视觉目的,它是蓝色的,但您应该将其 alpha 设置为 0 以使其透明。
  • 使用 createRigidArea 而不是 createXXXStrut(请参阅上面链接中的注释)。
  • 我使用了frame.setMinimumSize(frame.getPreferredSize())来不让窗口调整到比其内容更小的尺寸。这是可选的。
  • 根据 Java 命名约定,非 Final 字段和变量不应在名称中使用下划线 (_)。
  • 您没有指定水平拉伸(stretch)行为,因此它会执行任何操作。
  • 我仍然认为框布局不是最好的方法,或者至少根本不允许调整窗口大小(因此不处理额外的空间)。

关于java - 如何在盒子布局中使用VerticalGlue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26596839/

相关文章:

java - Java 中的 3D 绘图。 Java3D 或 Jmonkey

java - 在扩展 JFrame 的类中的另一个 JFrame 上绘制一条线

java - GridBag布局辅助

java - 如何让我的组件在执行时使用 JFrame 正确调整大小 Java eclipse GUI Builder

java - 修复 JTextArea 的高度

java - 从我的Android应用中打开youtube应用。如何传递身份证?

java - 浪的解释

java - 一一显示 HashMap 中的多个值

java - 从 jComboBox(Java 数据库)中选择时用记录填充 jTextField

java - JPA 和 EJB 延迟初始化字段