这是我的代码
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());
private final JPanel rightPanel_2 = new JPanel(new GridBagLayout());
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.setPreferredSize(new Dimension(1000, 550));
gbc.gridx = 1; gbc.gridy = 0;
this.add(rightPanel_1,gbc);
}
public final void constructRightPanel_2(){
rightPanel_2.setPreferredSize(new Dimension(800, 300));
gbc.gridheight = 3;
rightPanel_1.add(rightPanel_2,gbc);
}
public final void constructLeftPanelComponents(){
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);
}
}
我有两个问题:
答案 0 :(得分:5)
- 如何将所有这4个对象推到顶部?
醇>
您需要为组件分配权重:gbc.weightx
和gbc.weighty
。
- 为什么"用户图像" JLabel占用太多空间,或者更确切地说,为什么它的细胞高度太高了?
醇>
添加gbc.gridheight = 1
后,您忘记重置rightPanel_2
。此外,您将gbc.anchor
值设置为CENTER
和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(...)
。请参阅here和here。
我建议为每个新容器使用一个新的GridBagConstraints
(如果不是每个新组件),否则你会冒一些像你所拥有的那些讨厌的错误。该教程还提到:
正如您可能从上面的示例中猜到的那样,即使组件具有不同的约束,也可以为多个组件重用相同的
GridBagConstraints
实例。但是,建议您不要重复使用GridBagConstraints
,因为如果您忘记重置每个新实例的字段,这很容易导致您引入细微的错误。
当您设置GridBagConstraints
属性时,将保持不变。在某些时候将gridheight
设置为1将在设置后影响所有 add
调用,因此无需为每次调用将其再次设置为相同的值。每次设置为gridx
的{{1}}也是如此 - 一次实际上就足够了。我离开所有冗余调用的原因是,在添加组件之前有时更容易看到确切的位置,而不是在上次设置属性时搜索代码。
生产阶段的着色组件有助于了解GUI的真实外观。
编辑:有关常规代码的说明
在EDT上启动GUI(参见Concurrency in Swing):
0
根据Java命名约定,变量名称不应使用下划线(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);
});
}
),除非它们是常量。因此_
应为rightPanel_1
。
您正在创建相同边框的3倍rightPanel1
,并且当局部变量执行时,您也将它们保留为字段。您甚至可以在BorderFactory.createLineBorder(Color.BLACK, 1);
来电中创建边框。
我认为不是在一个地方设置所有边框,而是可以在配置它的地方设置每个组件的边框。在您的代码中,您将方法划分为匹配组件,因此在该方法中完全配置组件是有意义的。
将较长的方法拆分为较小的setBorder(...)
方法是处理可读性的绝佳方法。我希望我更多地看到它而不是100行组件初始化。但是,在您的情况下,如果您有一个共享对象(如final
),那么您必须小心它在方法之间的变化。
答案 1 :(得分:3)
尝试以下原则:
public class GridBagLayoutTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
test();
}
});
}
private static void test() {
JFrame frame = new JFrame("GridBagLayoutTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JLabel userImageLabel = new JLabel("User Image");
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 0;
gbc.weighty = 0;
gbc.insets.bottom = 80;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.PAGE_START;
contentPane.add(userImageLabel, gbc);
JButton updatePhotoButton = new JButton("Update Photo");
gbc.gridy++;
gbc.insets.bottom = 5;
gbc.fill = GridBagConstraints.HORIZONTAL;
contentPane.add(updatePhotoButton, gbc);
JPanel logHistoryPanel = new JPanel();
logHistoryPanel.setBorder(BorderFactory.createTitledBorder("Log History"));
logHistoryPanel.setPreferredSize(new Dimension(110, 100));
gbc.gridy++;
gbc.weighty = 0.001;
gbc.insets.bottom = 0;
contentPane.add(logHistoryPanel, gbc);
gbc.gridy++;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
contentPane.add(Box.createVerticalGlue(), gbc);
JPanel rightPanel = new JPanel();
rightPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
gbc.gridx = 1;
gbc.gridy = 0;
gbc.gridheight = 4;
gbc.weightx = 1;
gbc.insets.left = 5;
gbc.anchor = GridBagConstraints.CENTER;
contentPane.add(rightPanel, gbc);
frame.setContentPane(contentPane);
frame.setSize(new Dimension(500, 500));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
<强> UPD:强>
为什么建议包含SwingUtilities.invokeLater(new Runnable()。另外,我注意到你把所有的初始化都放在一个方法中。这是我应该练习的东西而不是在构造函数中调用我的方法我在帖子中做了什么?
SwingUtilities.invokeLater
肯定会这样做。