- 如何将这 4 个对象全部推到顶部?
您需要为组件分配权重:gbc.weightx
and gbc.weighty
.
- 为什么“用户图像”JLabel 占用太多空间,或者为什么它的单元格高度太高?
你忘记重置了gbc.gridheight = 1
添加后rightPanel_2
。另外,您还设置了gbc.anchor
价值CENTER
and PAGE_END
这会导致您的组件无法按您想要的方式堆叠。
我在代码中注释掉了应该删除的内容,并添加了上面解释的修复布局的代码:
public class HomeTopPanel extends JPanel {
// BUTTONS
private final JButton myAccountButton = new JButton("My Account");
private final JButton updatePhoto = new JButton("Update Photo");
// PANELS
private final JPanel rightPanel_1 = new JPanel(new GridBagLayout()) {
public Dimension getPreferredSize() {
return new Dimension(1000, 550);
};
};
private final JPanel rightPanel_2 = new JPanel(new GridBagLayout()) {
public Dimension getPreferredSize() {
return new Dimension(800, 300);
};
};
private final JPanel logHistoryPanel = new JPanel(new GridBagLayout());
// BORDERS
private final Border homeTopPanel_LineBorder = BorderFactory.createLineBorder(Color.BLACK, 1);
private final Border rightPanel1_LineBorder = BorderFactory.createLineBorder(Color.BLACK, 1);
private final Border rightPanel2_LineBorder = BorderFactory.createLineBorder(Color.BLACK, 1);
private final TitledBorder logHistoryPanel_TitledBorder = BorderFactory.createTitledBorder("Log History");
// LABELS
private final JLabel imageContainer = new JLabel("User Image");
// CONSTRAINTS
GridBagConstraints gbc = new GridBagConstraints();
// CONSTRUCTOR
public HomeTopPanel() {
// METHOD CALLS
this.setLayout(new GridBagLayout()); // setting of layout should ALWAYS come first before adding constraints and components
constructMyAccountButton();
constructRightPanel_1();
constructRightPanel_2();
constructLeftPanelComponents();
setRightPanelBorders();
}
public final void constructMyAccountButton() {
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.gridx = 0;
gbc.gridy = 0;
this.add(myAccountButton, gbc);
}
public final void constructRightPanel_1() {
rightPanel_1.setBackground(Color.RED);
// rightPanel_1.setPreferredSize(new Dimension(1000, 550));
gbc.fill = GridBagConstraints.BOTH; // Optional: used for the 2 right panels
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridx = 1;
gbc.gridy = 0;
this.add(rightPanel_1, gbc);
}
public final void constructRightPanel_2() {
rightPanel_2.setBackground(Color.BLUE);
// rightPanel_2.setPreferredSize(new Dimension(800, 300));
gbc.gridheight = 3;
rightPanel_1.add(rightPanel_2, gbc);
}
public final void constructLeftPanelComponents() {
gbc.fill = GridBagConstraints.NONE; // Remove if you didn't use it above
gbc.weightx = 0;
gbc.weighty = 0;
gbc.gridheight = 1;
gbc.gridx = 0;
gbc.gridy = 0;
// gbc.ipadx = 0;
// gbc.anchor = GridBagConstraints.PAGE_START;
rightPanel_1.add(imageContainer, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
// gbc.anchor = GridBagConstraints.CENTER;
rightPanel_1.add(updatePhoto, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
// gbc.anchor = GridBagConstraints.PAGE_END;
logHistoryPanel.setPreferredSize(new Dimension(110, 100));
rightPanel_1.add(logHistoryPanel, gbc);
}
private void setRightPanelBorders() {
rightPanel_1.setBorder(rightPanel1_LineBorder);
rightPanel_2.setBorder(rightPanel2_LineBorder);
logHistoryPanel.setBorder(logHistoryPanel_TitledBorder);
this.setBorder(homeTopPanel_LineBorder);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new HomeTopPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
(已编辑)有关您使用的注释GridBagLayout
:
@Override getPreferredSize()
而不是打电话setPreferredSize(...)
. See here https://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi and here https://stackoverflow.com/questions/10866762/use-of-overriding-getpreferredsize-instead-of-using-setpreferredsize-for-fix.
-
我建议使用新的GridBagConstraints
对于每个新容器(如果不是每个新组件),否则您将面临一些令人讨厌的错误的风险,就像您所拥有的那样。教程还提到:
正如您可能从上面的示例中猜到的那样,可以重用相同的内容GridBagConstraints
多个组件的实例,即使组件具有不同的约束。但建议不要重复使用GridBagConstraints
,因为如果您忘记为每个新实例重置字段,这很容易导致您引入微妙的错误。
当您设置一个GridBagConstraints
财产,它保留直至更改。设置gridheight
在某些时候变为 1 会影响all add
设置后调用,因此无需为每次调用再次将其设置为相同的值。这也适用于gridx
你设置为0
每次——实际上一次就足够了。我保留所有冗余调用的原因是,有时在添加组件之前更容易看到确切的位置,而不是搜索上次设置属性的代码。
在生产阶段为组件着色有助于了解 GUI 的真实外观。
编辑:关于您的通用代码的注释
-
在 EDT 上启动 GUI(请参阅Swing 中的并发 http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html):
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.add(new HomeTopPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
});
}
根据Java命名约定,变量名不应使用下划线(_
)除非它们是常数。所以rightPanel_1
应该rightPanel1
.
您正在创建 3 次相同的边框,BorderFactory.createLineBorder(Color.BLACK, 1);
当局部变量可以使用时,您也可以将它们保留为字段。您甚至可以只在内部创建边框setBorder(...)
call.
我认为,您可以在配置每个组件的位置设置其边框,而不是将所有边框设置在一处。在代码中,您划分了方法来匹配组件,因此在该方法中完全配置组件是有意义的。
将长方法分割成更小的方法final
方法是处理可读性的绝佳方法。我希望我看到的不仅仅是 100 行组件初始化。但是,就像您的情况一样,如果您有一个共享对象(例如GridBagConstraints
)那么你必须小心它在方法之间如何变化。