GridBag布局如何将组件推向北方

jor*_*dan 3 java swing layout-manager gridbaglayout

这是我的代码

 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);
}
}   
Run Code Online (Sandbox Code Playgroud)

这是我得到的: 在此输入图像描述

我有两个问题:

  1. 如何将所有这4个物体推到顶部?
  2. 为什么"用户形象"JLabel占用太多空间,或者为什么它的单元高度太高?

我想完成这个:

在此输入图像描述

然后把它推到顶部.我尝试使用插图和重量,但仍然无法得到我想要的结果.

我很感激任何帮助.此时,我不知道ipadx/ipady或weightx/weighty是否存在问题.

use*_*551 5

  1. 如何将所有这4个物体推到顶部?

您需要为组件分配权重:gbc.weightxgbc.weighty.

  1. 为什么"用户形象"JLabel占用太多空间,或者为什么它的单元高度太高?

gbc.gridheight = 1添加后忘了重置rightPanel_2.此外,您将gbc.anchor值设置为,CENTERPAGE_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);
    }
}
Run Code Online (Sandbox Code Playgroud)

(已编辑)关于您使用的注意事项GridBagLayout:

  • @Override getPreferredSize()而不是打电话setPreferredSize(...).看到这里这里.

  • 我建议GridBagConstraints为每个新容器使用一个新的容器(如果不是每个新组件),否则你冒着一些像你所拥有的那些讨厌的错误.该教程还提到:

    正如您可能从上面的示例中猜到的那样GridBagConstraints,即使组件具有不同的约束,也可以为多个组件重用相同的实例.但是,建议您不要重复使用GridBagConstraints,因为如果您忘记重置每个新实例的字段,这很容易导致您引入细微的错误.

    设置GridBagConstraints属性时,它会一直保留,直到更改为止.gridheight在某些时候将设置为1将影响设置后的所有 add调用,因此无需为每次调用将其再次设置为相同的值.这也适用于gridx0每次设置- 一次实际上就足够了.我离开所有冗余调用的原因是,在添加组件之前有时更容易看到确切的位置,而不是在上次设置属性时搜索代码.

  • 生产阶段的着色组件有助于了解GUI的真实外观.

编辑:关于通用代码的注释

  • 在EDT上启动GUI(请参阅Swing中的并发):

    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);
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 根据Java命名约定,变量名称不应使用underscores(_),除非它们是常量.所以rightPanel_1应该是rightPanel1.

  • 您正在创建相同边框的3倍,BorderFactory.createLineBorder(Color.BLACK, 1);并且在局部变量执行时您也将它们保留为字段.您甚至可以在setBorder(...)通话中创建边框.

  • 我认为不是在一个地方设置所有边框,而是可以在配置它的地方设置每个组件的边框.在您的代码中,您将方法划分为匹配组件,因此在该方法中完全配置组件是有意义的.

  • 将长方法拆分为较小的final方法是处理可读性的极好方法.我希望我更多地看到它而不是100行组件初始化.但是,就像你的情况一样,如果你有一个共享对象(比如GridBagConstraints),那么你必须要小心这些方法之间的变化.