简体   繁体   English

GridBagLayout为列提供了额外的余量

[英]GridBagLayout gives extra margin to column

i've been working with Swing for quite some time and i finally found the self confidence to learn GridBadLayout. 我已经和Swing一起工作了一段时间,终于找到了学习GridBadLayout的自信。

I'm still learning it, and in this case i can't understand why the following code is not responding as expected: in particular i can't understand why the layout is displaying the columns this way. 我仍在学习它,在这种情况下,我不明白为什么以下代码没有按预期方式响应:特别是我不明白为什么布局以这种方式显示列。

By running the snippet, you will se that the panels representing the italian flag are not positioned correctly: the last column(red part of the flag) is detached from the rest of the flag(white part of the flag). 通过运行摘要,您将发现代表意大利国旗的面板的位置不正确:最后一列(国旗的红色部分)与国旗的其余部分(国旗的白色部分)分离。 So, what am i doing wrong and what can i fix in order to represent correclty the flag? 那么,我在做错什么,为了代表正确的标志,我可以解决什么问题?

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class test extends JPanel {

    private GridBagConstraints gbc;
    private final int CELL_WIDTH = 90;
    private final int CELL_HEIGHT = 110;

    public test() {
        setLayout(new GridBagLayout());

        putBanner(0);

        putFlagRow(1);
        putFlagRow(2);
        putFlagRow(3);
        putFlagRow(4);
    }

    public JPanel getUserPanel(Color c) {
        JPanel ol = new JPanel();
        ol.setPreferredSize(new Dimension(CELL_WIDTH * 10, CELL_HEIGHT));
        ol.setBackground(c);
        return ol;
    }

    public JPanel gettestPanel() {
        JPanel ol = new JPanel();
        ol.setPreferredSize(new Dimension(CELL_WIDTH, CELL_HEIGHT));
        ol.setBackground(Color.white);
        return ol;
    }

    private void putFlagRow(int gridy) {
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = gridy;
        JPanel p1=gettestPanel();
        p1.setBackground(Color.green);
        add(p1, gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 3;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 4;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 5;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 6;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 7;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 8;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 9;
        gbc.gridy = gridy;
        JPanel p=gettestPanel();
        p.setBackground(Color.red);
        add(p, gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 10;
        gbc.gridy = gridy;
        add(gettestPanel(), gbc);
    }

    private void putBanner(int gridy) {
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = gridy;
        gbc.gridwidth = 1;
        add(gettestPanel(), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = gridy;
        gbc.gridwidth = 9;
        add(getUserPanel(Color.black), gbc);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagLayoutTest");
        frame.add(new test());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Besides understanding this particular issue and its cause, i wish to understand this, wich comes directly from GridBagLayout Oracle docs: 除了了解此特定问题及其原因外,我还希望了解这一点,它直接来自GridBagLayout Oracle文档:

weightx, weighty Specifying weights is an art that can have a significant impact on the appearance of the components a GridBagLayout controls. weightx,weighty 指定权重是一门艺术,可能会对GridBagLayout控件的组件的外观产生重大影响。 Weights are used to determine how to distribute space among columns (weightx) and among rows (weighty); 权重用于确定如何在列(权重)和行(权重)之间分配空间。 this is important for specifying resizing behavior. 这对于指定调整大小的行为很重要。 Unless you specify at least one non-zero value for weightx or weighty, all the components clump together in the center of their container. 除非您为weightx或weighty指定至少一个非零值,否则所有组件都将在其容器的中心聚集在一起。 This is because when the weight is 0.0 (the default), the GridBagLayout puts any extra space between its grid of cells and the edges of the container. 这是因为当权重为0.0(默认值)时,GridBagLayout会在其单元格网格和容器边缘之间放置任何多余的空间。 Generally weights are specified with 0.0 and 1.0 as the extremes: the numbers in between are used as necessary. 通常,权重的极限值设置为0.0和1.0:必要时使用中间的数字。 Larger numbers indicate that the component's row or column should get more space. 较大的数字表示组件的行或列应获得更多的空间。 For each column, the weight is related to the highest weightx specified for a component within that column, with each multicolumn component's weight being split somehow between the columns the component is in. Similarly, each row's weight is related to the highest weighty specified for a component within that row. 对于每一列,权重与该列中为组件指定的最高权重x有关,每个多列组件的权重均以某种方式在该组件所在的列之间分配。类似地,每一行的权重与为a所指定的最高权重有关。该行中的组件。 Extra space tends to go toward the rightmost column and bottom row. 多余的空间倾向于流向最右边的列和最下面的行。

Expressions like 像这样的表达

is an art 是一门艺术

and

the numbers in between are used as necessary 必要时使用中间的数字

really gives me the impression that not even the doc writer thought it was possible to teach the usage of such constraint. 确实给我的印象是,甚至文档撰写者都没有想到可以教这种约束的用法。 And that is no good 那不好

weightX and weighty are quite easy to use, but the tutorial doesn't help... Let's say that when you make a dialog and you pack() it, the components take a position and size and everything is ok (or not). weightX和weighty相当易于使用,但是本教程无济于事...假设当您创建一个对话框并对其进行pack()时,组件将占据一个位置和大小,并且一切正常(或不正常)。 What happens if you resize the dialog and make it bigger? 如果您调整对话框的大小并将其放大,会发生什么? Suddenly there's more space and the components must grow, and that's the moment when Swing looks the weight* parameters. 突然之间有更多的空间,组件也必须增加,这就是Swing查找weight*参数的时刻。

If a component has weightx=1.0 and the rest weightx=0.0 means that the first component gets all the new space and the second keeps its size. 如果某个组件的weightx=1.0 ,其余weightx=0.0意味着第一个组件获得所有新空间,第二个组件保持其大小。 If the components have weightx=0.5 means that the two components share the new size, 50% each one. 如果组件的weightx=0.5表示这两个组件共享新的大小,每个占50%。 If the components have values for weightx that united are bigger than 1.0 means that the components want more than the 100% of the new space, so... well, something magic... 如果组件的weightx值的总和大于1.0,则意味着组件需要的空间超过新空间的100%,所以...好吧,这很神奇...

Imagine you are doing a web browser. 假设您正在使用网络浏览器。 you want that the top panels with the tabs, buttons and menus keep alwais the same size while the center panel for the web page get all the new extra size, so you give to the center panel weight*=1.0 and weight*=0.0 for the top panel. 您希望带有选项卡,按钮和菜单的顶部面板保持相同的尺寸,而网页的中心面板获得所有新的额外尺寸,因此您将中间面板的weight*=1.0weight*=0.0设为顶部面板。

Try to don't assign more than 1.0 weight in any row or column and everything will be ok. 尝试在任何行或列中分配的权重不要超过1.0,一切都会好起来的。

the last column(red part of the flag) is detached from the rest of the flag(white part of the flag). 最后一列(标志的红色部分)与其余标志(标志的白色部分)分离。

One thing to do when debugging a GridBagLayout is to add a Border to the components so you can see how each cell is sized. 调试GridBagLayout时,要做的一件事是向组件添加Border ,以便您可以看到每个单元格的大小。 I added the following to your getTestPanel() method: 我将以下内容添加到您的getTestPanel()方法中:

ol.setBorder( new LineBorder(Color.BLUE) );

You can see the panel is sized properly but there is extra space around the panel. 您可以看到面板的尺寸正确,但是面板周围有多余的空间。

Then you look at your user panel: 然后,您查看用户面板:

ol.setPreferredSize(new Dimension(CELL_WIDTH * 10, CELL_HEIGHT));

And you will see the size is set to 10 cells even though you only set the gridwidth to 9 cells. 即使您仅将gridwidth设置为9个单元格,您也会看到大小设置为10个单元格。 So now the 9 cells must fit into the space of the user panel and it looks like the extra space is given to the last column of the 9 columns. 因此,现在9个单元格必须适合用户面板的空间,并且看起来这9列的最后一列有多余的空间。

The code should be: 代码应为:

//ol.setPreferredSize(new Dimension(CELL_WIDTH * 10, CELL_HEIGHT));
ol.setPreferredSize(new Dimension(CELL_WIDTH * 9, CELL_HEIGHT));

Another option would be to NOT give a preferred size to the user panel, but then use the "fill" constraint so the user panel will now take up the same space as the nine columns. 另一个选择是不为用户面板提供首选的大小,而是使用“填充”约束,以便用户面板现在将占用与九列相同的空间。

weightx, weighty Specifying weights is an art... weightx,weighty指定重量是一门艺术...

This is not related to your problem. 这与您的问题无关。 To see this effect, drag the frame larger. 若要查看此效果,请将框架拖动更大。 Now all the entire panel will be positioned in the center of the frame since none of your component use the weightx/weighty constraints. 现在,由于您的组件都没有使用weightx / weighty约束,因此整个面板都将放置在框架的中央。 This means none of the components will grow to fill the empty space if the frame. 这意味着如果使用框架,则所有组件都不会增长以填充空白空间。

If one of the components has a weightx constraint of 1.0 then that column will expand and fill the extra space as the frame is resized. 如果组件之一的权重约束为1.0,则在调整框架大小时,该列将扩展并填充额外的空间。

I think what you are trying to achieve, is something like this: 我认为您想要达到的目标是这样的:

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test extends JPanel {

    private static final long serialVersionUID = 1L;

    public Test() {
        setLayout(new GridBagLayout());
        putBanner(0);
        putFlagRow(1);
    }

    public JPanel getUserPanel(Color c) {
        JPanel panel = new JPanel();
        panel.setBackground(c);
        return panel;
    }

    private void putFlagRow(int gridy) {
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = gridy;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 0.5;
        gbc.weighty = 1;
        add(getUserPanel(Color.green), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = gridy;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1;
        gbc.weighty = 1;
        add(getUserPanel(Color.white), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = gridy;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 0.5;
        gbc.weighty = 1;
        add(getUserPanel(Color.red), gbc);
    }

    private void putBanner(int gridy) {
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = gridy;
        gbc.ipady = 50;
        gbc.fill = GridBagConstraints.BOTH;
        add(getUserPanel(Color.white), gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = gridy;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1;
        add(getUserPanel(Color.black), gbc);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagLayoutTest");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(new Test());
        frame.setSize(450, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

The GridBagLayout is a very complex and powerful way to align your content, its not that easy to explain it in two sentences, so the easiest way, I think, is to play around or watch some Tutorials, but I'll try: GridBagLayout是对齐内容的一种非常复杂而强大的方法,用两句话来解释它并不是那么容易,所以我认为最简单的方法是玩转或观看一些教程,但是我将尝试:
You have to think like you are editing an Excel table. 您必须认为自己就像在编辑Excel表一样。 If you resize one cells width, the whole column will have this width, same for the rows/height. 如果您调整一个单元格的宽度,整个列的宽度将与行/高度相同。 So now you do not have to add tones of white planes, you only need one and resize it properly. 因此,现在您不必添加白色飞机的色调,只需要一个并适当调整其大小即可。
Next thing is not to set fixed sizes, the layouts will do it for you, that's what they are for or use absolute coordinates (no layout: setLayout(null) ). 接下来的事情不是设置固定的大小,布局将为您做到这一点,这就是它们的用途或使用绝对坐标(无布局: setLayout(null) )。
So now you have to tell the GridBagLayout how to align the components. 因此,现在您必须告诉GridBagLayout如何对齐组件。 There are different variables for different alignments. 不同的对齐方式有不同的变量。 First of all (you should already know) gridx and gridy hold the position of the component (in Excel something like A1 or C12). 首先(您应该已经知道), gridxgridy保持组件的位置(在Excel中类似A1或C12)。 Than you can 'combine cells' with gridwidth and gridheight . 比起您可以用gridwidthgridheight来“组合单元格”。
So now your component is positioned, but it would not change its size with the window's size. 因此,现在您的组件已定位,但不会随着窗口的大小而改变其大小。 Until know the cell has only the size of its component's getPreferredSize() . 直到知道该单元格只有其组件的getPreferredSize()的大小。 weightx and weighty are the next variables to look at. weightxweighty是接下来要查看的变量。 Those define how much of the leftover space should be used. 这些定义了应使用多少剩余空间。 For example you have two components (horizontally side by side) and their preferred width summed is 300px, but the window has a width of 1000px, 700px wouldn't be used. 例如,您有两个组件(水平并排),它们的首选宽度总和为300px,但是窗口的宽度为1000px,则不会使用700px。 So if you now set both weightx to 1, they trying to use hundred percent of leftover pixels, but they can not have both 700px additionally, so everyone receives 350px. 因此,如果现在将两个weightx都设置为1,它们将尝试使用100%的剩余像素,但它们不能同时具有700px,因此每个人都得到350px。 If you now set one weightx to 0 and the other one to 1, the first gets no additionally pixels and the other all 700px. 如果您现在将一个weightx设置为0,将另一个weightx设置为1,则第一个不会获得额外的像素,而另一个全为700px。
If you tried it until now, you will see much empty spaces between the panels, thats because only the cells are resized, but not their content. 如果您一直尝试到现在,您将在面板之间看到很多空白,这是因为仅调整了单元格的大小,但未调整其内容。 Now you can set were the component should be displayed in its cell with anchor (for example GridBagConstraints.NORTH / SOUTH / SOUTHEAST ), but then you still have those empty spaces and no flag has an empty space, what your looking for is fill . 现在,您可以设置要在组件中使用anchor显示组件的位置(例如GridBagConstraints.NORTH / SOUTH / SOUTHEAST ),但是您仍然有这些空白,没有标志有空白,您要找的是fill
fill lets you chose, what to do with the empty space in the cell. fill让您选择如何处理单元格中的空白区域。 With GridBagConstraints.NONE the component would not be resized, HORIZONTAL only resizes the width to the width of the cell ( VERTICAL only the height) and BOTH resize the component to fit the cells size. GridBagConstraints.NONE组件将不会被调整大小, HORIZONTAL仅调整大小宽度与单元格的宽度( VERTICAL仅高度)和BOTH调整大小以适合细胞大小的组件。
The variable insets adds empty insets, for example you chose to set fill to BOTH , but sill want to have empty space above the component (the inset is fixed, if you want a dynamic inset, you have to workaround by adding empty components with the specific GridBagConstraints to align the inset you want to display). 变量insets添加空的inset,例如,您选择将fill设置为BOTH ,但是窗台想要在组件上方留有空白空间(inset是固定的,如果要动态inset,则必须通过在空白处添加空组件来解决。特定的GridBagConstraints来对齐要显示的插图)。
ipadx and ipady are fixed values to be added to the size of the cell, for example ipadx is set to 5, the cell will have at least the width of the component's minimum width plus ipadx 's 5px. ipadxipady是要添加到单元格大小的固定值,例如ipadx设置为5,该单元格至少具有组件最小宽度的宽度加上ipadx的5px。 In other words the width of the cell will always be at least 5px bigger than the component's width (if fill is set to BOTH or HORIZONTAL the component would afterwards be resized to the new width). 换句话说,单元格的宽度将始终至少比组件的宽度大5像素(如果将fill设置为BOTHHORIZONTAL ,组件随后将被调整为新的宽度)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM