如何填写有关布局管理器的剩余空间?

BWC*_*maJ 4 java swing layout-manager

我最近一直在开发Swing应用程序.我遇到了布局管理器的问题.我似乎无法弄清楚如何使布局中的组件一直增长到其父容器的边缘.让我解释.

假设我在一行中有8个按钮.根据窗口大小将确定它们是否占用了所有空间.GBL我找到了中心左右两侧的空间.BoxLayout通常在右侧空间.这可能是由于他们的锚点或对齐.

我认为问题是因为当所有组件具有相同的设置时,它会尝试为每个组件提供相同的空间.因此,不能将多余的空间平均分配给他们将其遗漏的每个组件.

我想知道是否有一个解决方案.就像空间那么小,我希望有一种方法可以让最后一个组件吃掉它或者在组件之间将它分开.

以下是显示问题的示例代码.请注意,当您调整面板大小时,您将获得额外的空间.

public class LeftoverExample {

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                LeftoverExample.createGUI();
            }
        });
    }

    public static void createGUI(){
        JFrame jF = new JFrame();
        jF.setSize(new Dimension(1333,500));
        jF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create ContentPane
        JPanel contentPane = new JPanel();
        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS));

        GridBagLayout gBL = new GridBagLayout();
        gBL.columnWidths = new int[]{0};
        gBL.rowHeights = new int[]{50, 50, 50 , 50};
        contentPane.setLayout(gBL);

        //Initial Constraints
        GridBagConstraints gBC = new GridBagConstraints();
        gBC.fill = GridBagConstraints.BOTH;
        gBC.gridx = 0;
        gBC.gridy = 0;
        gBC.weightx = 1;
        gBC.weighty = 0;
        gBC.insets = new Insets(10, 0, 10, 0);

        //Add Examples to ContentPane
        contentPane.add(LeftoverExample.createGBL(false), gBC);
        gBC.gridy++;
        contentPane.add(LeftoverExample.createGBL(true), gBC);
        gBC.gridy++;
        contentPane.add(LeftoverExample.createBoxLayout(false), gBC);
        gBC.gridy++;
        contentPane.add(LeftoverExample.createBoxLayout(true), gBC);

        //Final
        jF.setContentPane(contentPane);
        jF.setVisible(true);
    }

    private static JComponent createGBL(boolean addButtons){
        //GBL Example
        JLabel gBLJLabel = new JLabel("GridBagLayout");
        gBLJLabel.setVerticalAlignment(SwingConstants.CENTER);
        gBLJLabel.setLayout(new BoxLayout(gBLJLabel, BoxLayout.X_AXIS));
        gBLJLabel.setBackground(Color.CYAN);
        gBLJLabel.setOpaque(true);
        gBLJLabel.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
        GridBagLayout gBL = new GridBagLayout();
        gBL.columnWidths = new int[]{0};
        gBL.rowHeights = new int[]{50};
        gBLJLabel.setLayout(gBL);

        //Initial Constraints
        GridBagConstraints gBC = new GridBagConstraints();
        gBC.fill = GridBagConstraints.BOTH;
        gBC.gridx = 0;
        gBC.gridy = 0;
        gBC.weightx = 1;
        gBC.weighty = 0;
        gBC.insets = new Insets(0, 0, 0, 0);

        //Add to GBL Panel
        if(addButtons){
            LeftoverExample.addButtons(gBLJLabel, gBC);
            LeftoverExample.addButtons(gBLJLabel, gBC);
            LeftoverExample.addButtons(gBLJLabel, gBC);
            LeftoverExample.addButtons(gBLJLabel, gBC);
            LeftoverExample.addButtons(gBLJLabel, gBC);
            LeftoverExample.addButtons(gBLJLabel, gBC);
        }
        return gBLJLabel;
    }

    private static JComponent createBoxLayout(boolean addButtons){
        //BoxLayout Example
        JLabel boxLayoutJL = new JLabel("BOX_LAYOUT");
        boxLayoutJL.setVerticalAlignment(SwingConstants.CENTER);
        boxLayoutJL.setLayout(new BoxLayout(boxLayoutJL, BoxLayout.X_AXIS));
        boxLayoutJL.setBackground(Color.GREEN);
        boxLayoutJL.setOpaque(true);
        boxLayoutJL.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));

        //Add to BoxLayout Panel
        if(addButtons){
            LeftoverExample.addButtons(boxLayoutJL);
            LeftoverExample.addButtons(boxLayoutJL);
            LeftoverExample.addButtons(boxLayoutJL);
        }
        return boxLayoutJL;
    }

    private static JButton createButton(Color c){
        JButton jB = new JButton();
        jB.setBackground(c);
        jB.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
        return jB;
    }

    private static void addButtons(JComponent jC, GridBagConstraints gBC){
        //Create Buttons
        Color[] colorA = {Color.RED, Color.BLUE, Color.BLACK, Color.GREEN};
        for(Color c : colorA){
            jC.add(LeftoverExample.createButton(c), gBC);
            gBC.gridx++;
        }
    }

    private static void addButtons(JComponent jC){
        //Create Buttons
        Color[] colorA = {Color.BLUE, Color.BLACK, Color.GREEN, Color.RED};
        for(Color c : colorA){
            jC.add(LeftoverExample.createButton(c));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

看看每个西侧和东侧是否有一些空间,父级(在本例中为JLabel)占用但按钮不占用.我希望能够让按钮占用那个空间.

图片显示示例:

d.j*_*own 5

问题是由Swing使用维度的整数值而不是双倍引起的.

考虑到这一事实,容器宽度除法的余数r除以它包含的Component(在你的情况下是JButton对象)对象的数量,可以用来将第一个r Component对象的大小增加1来补偿.显然这意味着第一个r Component对象将比另一个大+1 Components,但这不应该是显而易见的.

为了更新Component对象的宽度,我们需要访问容器(例如JPanel)和Component我们希望更新的所有对象.在我的例子中,我将使用a List来实现此目的.

这是一种Component相应调整对象大小的工作方法.

private static void fixComponentWidths(Component container,
    List<? extends Component> componentList, int componentHeight) {

    if (!componentList.isEmpty()) { // Avoid possible division by zero

        // get the desired component width for the container using integer division
        int baseComponentWidth = container.getWidth() / componentList.size();

        // find the remainder
        int remainder = container.getWidth() % componentList.size();

        // update all the components
        for (int i = 0; i < componentList.size(); i++) {

            // the component width will be the base width plus 1 iff i < remainder
            int componentWidth = baseComponentWidth;
            if (i < remainder) {
                componentWidth++;
            }

            // update the maximum size
            componentList.get(i).setMaximumSize(new Dimension(componentWidth, componentHeight));
        }

        // be sure to revalidate otherwise it may not work
        container.revalidate();
    }
}
Run Code Online (Sandbox Code Playgroud)

为了使其适用于调整大小,ComponentListener必须为我们的容器实现.这可能是JFrame或只是一个JPanel(根据我的例子).注意,只有componentResized(ComponentEvent)方法需要实现此任务.

buttonContainer.addComponentListener(new ComponentListener() {
    @Override
    public void componentResized(ComponentEvent ce) { // just implementing this
        fixComponentWidths(buttonContainer, buttons, BUTTON_HEIGHT);
        // where buttonContainer is a JPanel,
        // buttons is a List of JButtons
        // BUTTON_HEIGHT, well the height of the button!
    }

    @Override
    public void componentMoved(ComponentEvent ce) { // not needed
    }

    @Override
    public void componentShown(ComponentEvent ce) { // not needed
    }

    @Override
    public void componentHidden(ComponentEvent ce) { // not needed
    }
});
Run Code Online (Sandbox Code Playgroud)

这就是所需要的一切.但对于完整性这里有一个小例子,根据笔者的提问,随后的一个子类JPanel,它使用一个BoxLayout可用于解决此问题的两个BoxLayout.X_AXISBoxLayout.Y_AXIS.

完整的例子

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class FillExample extends JFrame {

    private static final int FRAMEL_DEFAULT_WIDTH = 700;
    private static final int FRAME_DEFAULT_HEIGHT = 400;

    private static final int BUTTON_HEIGHT = Integer.MAX_VALUE;

    private final List<JButton> buttons;

    public FillExample() {
        buttons = new ArrayList<>();
    }

    public void createAndShow() {
        setTitle("Fill Example");
        setSize(FRAMEL_DEFAULT_WIDTH, FRAME_DEFAULT_HEIGHT);

        final JPanel buttonContainer = new JPanel();
        buttonContainer.setLayout(new BoxLayout(buttonContainer, BoxLayout.X_AXIS));

        for (int i = 0; i < 3; i++) {
            addButtons(buttonContainer);
        }

        getContentPane().add(buttonContainer);

        buttonContainer.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent ce) {
                fixComponentWidths(buttonContainer, buttons, BUTTON_HEIGHT);
            }

            @Override
            public void componentMoved(ComponentEvent ce) {
            }

            @Override
            public void componentShown(ComponentEvent ce) {
            }

            @Override
            public void componentHidden(ComponentEvent ce) {
            }
        });

        setVisible(true);
    }

    private static void fixComponentWidths(Component container, List<? extends Component> componentList, int componentHeight) {
        if (!componentList.isEmpty()) {
            int baseComponentWidth = container.getWidth() / componentList.size();
            int remainder = container.getWidth() % componentList.size();
            for (int i = 0; i < componentList.size(); i++) {
                int componentWidth = baseComponentWidth;
                if (i < remainder) {
                    componentWidth++;
                }
                componentList.get(i).setMaximumSize(new Dimension(componentWidth, componentHeight));
            }
            container.revalidate();
        }
    }

    private void addButtons(JComponent component) {
        Color[] colorA = {Color.RED, Color.BLUE, Color.BLACK, Color.GREEN};
        for (Color c : colorA) {
            JButton button = createButton(c);
            buttons.add(button);
            component.add(button);
        }
    }

    private static JButton createButton(Color color) {
        JButton button = new JButton();
        button.setBackground(color);
        button.setMaximumSize(new Dimension(Integer.MAX_VALUE, BUTTON_HEIGHT));
        return button;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new FillExample().createAndShow();
            }
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

FillBoxLayoutPanel

这个小类可以用来快速解决这个BoxLayout.X_AXISBoxLayout.Y_AXIS.注意,该类创建BoxLayout并且LayoutManager无法更改.

Component可以使用add(Component comp)和将对象添加到面板中add(Component comp, int index).注意,并非所有add方法都被覆盖,应该仔细使用该类.

import java.awt.Component;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JPanel;

public class FillBoxLayoutPanel extends JPanel {

    public static final int X_AXIS = BoxLayout.X_AXIS;
    public static final int Y_AXIS = BoxLayout.Y_AXIS;

    private final List<Component> components;

    private final int direction;
    private boolean layoutSet;

    public FillBoxLayoutPanel(int direction) {
        components = new ArrayList<>();
        this.direction = direction;
        setLayout(new BoxLayout(this, direction));
        layoutSet = true;
        addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent ce) {
                adjustComponents();
            }

            @Override
            public void componentMoved(ComponentEvent ce) {
            }

            @Override
            public void componentShown(ComponentEvent ce) {
            }

            @Override
            public void componentHidden(ComponentEvent ce) {
            }
        });
    }

    @Override
    public void setLayout(LayoutManager mgr) {
        if (layoutSet) {
            throw new UnsupportedOperationException("FillPanel's layout manager cannot be changed.");
        } else {
            super.setLayout(mgr);
        }
    }

    @Override
    public Component add(Component comp) {
        comp = super.add(comp);
        components.add(comp);
        return comp;
    }

    @Override
    public Component add(Component comp, int i) {
        comp = super.add(comp, i);
        components.add(i, comp);
        return comp;
    }

    private void adjustComponents() {            
        if (!components.isEmpty()) {
            int size = direction == X_AXIS ? getWidth() : getHeight();
            int baseComponentSize = size / components.size();
            int remainder = size % components.size();

            for (int i = 0; i < components.size(); i++) {
                int componentSize = baseComponentSize;
                if (i < remainder) {
                    componentSize++;
                }
                Dimension dimension;
                if (direction == X_AXIS) {
                    dimension = new Dimension(componentSize, components.get(i).getHeight());
                } else {                    
                    dimension = new Dimension(components.get(i).getWidth(), componentSize);
                }
                components.get(i).setMaximumSize(dimension);
            }
            revalidate();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)