我正在尝试构建一个简单的面板,我将在其中添加一些字段并捕获一些用户数据。我通常使用 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
对象,行为都是相同的。
这就是我在渲染时看到的情况,并且表单变得比控件所需的更大。我希望垂直粘合填充“确定”按钮下方的空间,以将控件保持在表单顶部。
最佳答案
我复制粘贴了您的代码并添加了 main
方法:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new EmailPanel());
frame.pack();
frame.setVisible(true);
}
这是结果:
有或没有行 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);
}
}
说明:
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/