布局管理器,用于垂直和水平排列可变大小的组件
Layout Manager for lining up variably-sized components vertically and horizontally
我正在尝试为数据库中的 adding/editing 用户制作一个相当基本的面板。为了做到这一点,我想在左侧为不同的字段设置多个标签,在右侧为该字段设置相应的控件。 (因此,左侧可能会显示 "Username"、"User Type"、"Expiration Date" 等内容,相关的右侧将有一个文本面板、一个下拉列表和一个日历小部件.)
我 运行 遇到的问题是我希望它们水平排列(一个标签及其关联 "control areas" 应该从同一行开始)和垂直排列(所有标签应该从同一条垂直线开始,所有控制区域应该从同一条垂直线开始。)不过,有些控制区域比其他区域大或小;许多只包含一个文本面板,而其他的则有诸如单选按钮、日历小部件等与之关联的东西。
此外,所需的字段类型经常变化,并且根据上下文(例如是创建新用户还是编辑旧用户,以及控制用户的权限级别),其中一些字段可能被排除在外。所以,我想要的东西在很大程度上会自行安排 - 如果我必须非常手动地设置位置,我希望事情会因为部分被排除在外而中断。
我想看到的是一个布局管理器,基本上可以让我在灵活的网格上设置坐标,然后自动调整网格的大小以向每个元素提供最小值 space,同时仍然保持网格线笔直。这样我就可以简单地保留一个控件列表及其相关标签,并以编程方式构建面板,以便 labels/controls 始终分配给相同的行。
虽然我还没有弄清楚如何使用任何布局管理器来做到这一点:GridLayout
似乎要求所有内容都具有相同的大小,并且 BoxLayout
想要垂直排列或水平但不是两者。因此,我一直发现我的行排列但没有垂直对齐,或者错误的标签与错误的控件对齐。
有什么建议吗?
GridBagLayout
是实现此目的的最简单方法。它不是最直观的布局管理器:您需要在添加时为每个组件指定一个 'constraint'。有一些方法可以指定相对于前一个组件的位置,但我倾向于使用明确的 gridx
和 gridy
值来确保您确切知道事情的去向。您可以有一个方法来添加标签和组件并移动到下一行,以便包含此逻辑:
private final JPanel pane = new JPanel(new GridBagLayout());
private final GridBagConstraints c = new GridBagConstraints();
private void addLabelledComponent(String label, Component component) {
c.gridx = 0;
pane.add(new JLabel(label), c);
c.gridx = 1;
pane.add(component, c);
c.gridy++;
}
有关更多详细信息,例如定义对齐方式、填充、跨行和跨列等,请参阅 How To Use GridBagLayout。
这是一个示例,如您所见,有 2 个正常大小的行、1 个中等大小的行和 1 个较大(较高)的行,顺序不同,我认为这与您想要做的类似
行高由GridBagConstraints
的ipady
属性决定,你可以在How to use GridBagLayout and the docs
上阅读更多内容
我没怎么用过GridBagLayout
,所以可能有些地方可以跳过或改进,但为了有这个例子,下面是代码的输出:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GridBagLayoutExample {
private JPanel contentPane;
private JFrame frame;
private JLabel label;
private JTextField field;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GridBagLayoutExample().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame("GridBagLayout Example");
contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("A small label");
field = new JTextField();
c.insets = new Insets(0, 10, 0, 10);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0;
c.gridx = 0;
c.gridy = 0;
contentPane.add(label, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
c.gridwidth = 2;
contentPane.add(field, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 1;
c.ipady = 20;
contentPane.add(new JLabel("Another but much larger JLabel"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 1;
c.ipady = 20;
c.gridwidth = 2;
contentPane.add(new JButton("And including a larger JButton"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 2;
c.ipady = 60;
contentPane.add(new JLabel("A TALLER ROW!"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 2;
c.ipady = 60;
c.gridwidth = 2;
contentPane.add(new JTextField(), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 3;
c.ipady = 0;
contentPane.add(new JLabel("Another normal row"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 3;
c.gridwidth = 2;
contentPane.add(new JTextField(), c);
frame.add(contentPane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
我希望你现在心里有一个想法,如果你还有疑问,问另一个(更具体的)问题,包括你的 mcve
我正在尝试为数据库中的 adding/editing 用户制作一个相当基本的面板。为了做到这一点,我想在左侧为不同的字段设置多个标签,在右侧为该字段设置相应的控件。 (因此,左侧可能会显示 "Username"、"User Type"、"Expiration Date" 等内容,相关的右侧将有一个文本面板、一个下拉列表和一个日历小部件.)
我 运行 遇到的问题是我希望它们水平排列(一个标签及其关联 "control areas" 应该从同一行开始)和垂直排列(所有标签应该从同一条垂直线开始,所有控制区域应该从同一条垂直线开始。)不过,有些控制区域比其他区域大或小;许多只包含一个文本面板,而其他的则有诸如单选按钮、日历小部件等与之关联的东西。
此外,所需的字段类型经常变化,并且根据上下文(例如是创建新用户还是编辑旧用户,以及控制用户的权限级别),其中一些字段可能被排除在外。所以,我想要的东西在很大程度上会自行安排 - 如果我必须非常手动地设置位置,我希望事情会因为部分被排除在外而中断。
我想看到的是一个布局管理器,基本上可以让我在灵活的网格上设置坐标,然后自动调整网格的大小以向每个元素提供最小值 space,同时仍然保持网格线笔直。这样我就可以简单地保留一个控件列表及其相关标签,并以编程方式构建面板,以便 labels/controls 始终分配给相同的行。
虽然我还没有弄清楚如何使用任何布局管理器来做到这一点:GridLayout
似乎要求所有内容都具有相同的大小,并且 BoxLayout
想要垂直排列或水平但不是两者。因此,我一直发现我的行排列但没有垂直对齐,或者错误的标签与错误的控件对齐。
有什么建议吗?
GridBagLayout
是实现此目的的最简单方法。它不是最直观的布局管理器:您需要在添加时为每个组件指定一个 'constraint'。有一些方法可以指定相对于前一个组件的位置,但我倾向于使用明确的 gridx
和 gridy
值来确保您确切知道事情的去向。您可以有一个方法来添加标签和组件并移动到下一行,以便包含此逻辑:
private final JPanel pane = new JPanel(new GridBagLayout());
private final GridBagConstraints c = new GridBagConstraints();
private void addLabelledComponent(String label, Component component) {
c.gridx = 0;
pane.add(new JLabel(label), c);
c.gridx = 1;
pane.add(component, c);
c.gridy++;
}
有关更多详细信息,例如定义对齐方式、填充、跨行和跨列等,请参阅 How To Use GridBagLayout。
这是一个示例,如您所见,有 2 个正常大小的行、1 个中等大小的行和 1 个较大(较高)的行,顺序不同,我认为这与您想要做的类似
行高由GridBagConstraints
的ipady
属性决定,你可以在How to use GridBagLayout and the docs
我没怎么用过GridBagLayout
,所以可能有些地方可以跳过或改进,但为了有这个例子,下面是代码的输出:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GridBagLayoutExample {
private JPanel contentPane;
private JFrame frame;
private JLabel label;
private JTextField field;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GridBagLayoutExample().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame("GridBagLayout Example");
contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("A small label");
field = new JTextField();
c.insets = new Insets(0, 10, 0, 10);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0;
c.gridx = 0;
c.gridy = 0;
contentPane.add(label, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
c.gridwidth = 2;
contentPane.add(field, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 1;
c.ipady = 20;
contentPane.add(new JLabel("Another but much larger JLabel"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 1;
c.ipady = 20;
c.gridwidth = 2;
contentPane.add(new JButton("And including a larger JButton"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 2;
c.ipady = 60;
contentPane.add(new JLabel("A TALLER ROW!"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 2;
c.ipady = 60;
c.gridwidth = 2;
contentPane.add(new JTextField(), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 3;
c.ipady = 0;
contentPane.add(new JLabel("Another normal row"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 3;
c.gridwidth = 2;
contentPane.add(new JTextField(), c);
frame.add(contentPane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
我希望你现在心里有一个想法,如果你还有疑问,问另一个(更具体的)问题,包括你的 mcve