Обработка превышения/внешнего пространства в GridLayout

При использовании GridLayout он равномерно распределяет пространство своего контейнера между элементами строки и столбца. Однако, когда вычисление ширины ячейки не получается целым числом, избыточное пространство помещается между краями контейнера и его содержимым таким образом, что содержимое контейнера центрируется GridLayout.

На этом изображении вы можете видеть превышение пространства (окрашено зеленым цветом):

https://i.stack.imgur.com/UTDpT.png

Поскольку размер кадра перетаскивается на 233x233, LayoutManager будет предлагать каждому компоненту пол (233/20) = 11 пикселей по высоте и ширине. При этом 233% 20 = 13 пикселей превышают и ставятся по краям.

Это код для создания кадра на картинке:

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    GridLayout layout = new GridLayout(20, 0);
    layout.setHgap(0);
    layout.setVgap(0);
    frame.setLayout(layout);
    for (int j = 0; j < 20; j++) {
        for (int i = 0; i < 20; i++) {
            JPanel panel = new JPanel();
            panel.setBackground((i + j) % 2 == 0 ? Color.BLACK : Color.WHITE);
            frame.add(panel);
        }
    }
    frame.pack();
    frame.getContentPane().setBackground(Color.GREEN);
    frame.setVisible(true);

Поэтому мне интересно, есть ли простой способ сделать контейнер «обрезным» или выровнять таким образом, чтобы это превышение пространства не отображалось, а вместо этого размер контейнера изменялся, чтобы идеально соответствовать его содержимому.


person Reizo    schedule 29.12.2016    source источник
comment
AFAIU a GridBagLayout обрабатывает дополнительные пиксели пространства лучше, чем GridLayout. Назначая веса компонентам, мы можем контролировать, какие столбцы и строки первыми получат дополнительное пространство.   -  person Andrew Thompson    schedule 29.12.2016
comment
Это правильно, но я хочу сохранить преимущество GridLayout, предлагающего каждую ячейку одинакового размера, чего не было бы, если бы использовались GridBagLayout и другие различные панели в каждой ячейке.   -  person Reizo    schedule 29.12.2016


Ответы (1)


Это верно, но я хочу сохранить преимущество GridLayout, предлагающего каждую ячейку одинакового размера,

Да, вы не можете иметь это в обоих направлениях.

  1. Если вы хотите, чтобы каждая ячейка была одинакового размера, вы увидите фон. Одним из вариантов было бы сделать панель непрозрачной, чтобы вы не видели фон панели.

  2. Если вы хотите полностью заполнить доступную область компонентами, то некоторые компоненты должны быть другого размера на один пиксель.

Для реализации пункта 2, возможно, вам будет достаточно легко использовать этот пример:

import java.awt.*;
import javax.swing.*;

public class BoardTest
{
    private static void createAndShowGUI()
    {
        Float constraint = new Float(1);

        RelativeLayout boardLayout = new RelativeLayout(RelativeLayout.Y_AXIS);
        boardLayout.setRoundingPolicy( RelativeLayout.EQUAL );
        boardLayout.setFill(true);

        JPanel board = new JPanel(boardLayout);
        board.setBackground(Color.GREEN);

        RelativeLayout rowLayout = new RelativeLayout(RelativeLayout.X_AXIS);
        rowLayout.setRoundingPolicy( RelativeLayout.EQUAL );
        rowLayout.setFill(true);

        for (int j = 0; j < 20; j++)
        {
            JPanel row = new JPanel( rowLayout );

            for (int i = 0; i < 20; i++)
            {
                JPanel square = new JPanel();
                square.setBackground((i + j) % 2 == 0 ? Color.BLACK : Color.WHITE);
                row.add(square, constraint);
            }

            board.add(row, constraint);
        }

        JFrame frame = new JFrame("BoardTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(board);
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

Он использует класс Relative Layout, который позволяет вам управлять тем, как дополнительные пиксели выделяются каждому из компонентов.

person camickr    schedule 29.12.2016
comment
Это то, что я искал, спасибо! Либо пиксели должны быть добавлены к отдельным компонентам (точно так же, как в вашем решении), либо размер содержащей панели должен быть изменен до следующего более низкого (/ более высокого) подходящего размера. - person Reizo; 02.01.2017