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

时间:2016-01-13 15:09:36

标签: 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);
}
}   

这是我得到的: enter image description here

我有两个问题:

  1. 如何将所有这4个对象推到顶部?
  2. 为什么"用户图像" JLabel占用太多空间,或者更确切地说,为什么它的细胞高度太高了?
  3. 我想完成这个:

    enter image description here

    然后将其推到顶部。我尝试使用插图和重量但仍然无法获得我想要的结果。

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

2 个答案:

答案 0 :(得分:5)

  
      
  1. 如何将所有这4个对象推到顶部?
  2.   

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

  
      
  1. 为什么"用户图像" JLabel占用太多空间,或者更确切地说,为什么它的细胞高度太高了?
  2.   

添加gbc.gridheight = 1后,您忘记重置rightPanel_2。此外,您将gbc.anchor值设置为CENTERPAGE_END,这会导致您的组件无法根据需要进行堆叠。

我在你的代码中注释了应删除的东西,并添加了我上面解释的修复布局的代码:

enter image description here

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(...)。请参阅herehere

  • 我建议为每个新容器使用一个新的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);
    }
}

GridBagLayoutTest

<强> UPD:

  

为什么建议包含SwingUtilities.invokeLater(new Runnable()。另外,我注意到你把所有的初始化都放在一个方法中。这是我应该练习的东西而不是在构造函数中调用我的方法我在帖子中做了什么?

  1. 您使用图形和UI执行的所有操作都应在AWT thread中执行。 SwingUtilities.invokeLater肯定会这样做。
  2. 组件的初始化更多是关于样式而不是规则。但是,正如@ user1803551所说,“我建议为每个新容器使用一个新的GridBagConstraints(如果不是每个新组件),否则你冒着一些像你所拥有的那些讨厌的错误。”