Небольшое дополнительное пространство вокруг JPanel, когда оно должно заполнить JFrame - PullRequest
0 голосов
/ 16 апреля 2020

Я сделал MRE, которое вы можете найти внизу, а также файл изображения, который я использую. Не уверен, что было бы лучше просто загрузить мою папку sr c, но кто-то может дать мне знать, если это нормально. Во-первых, он заполняет JFrame. Однако есть подвох. Он заполняется должным образом только тогда, когда размеры области содержимого, я думаю, кратны 54. У меня есть прикрепленная картинка, потому что ее намного легче увидеть, чем объяснить.

enter image description here

Теперь, если я изменю размер JFrame. Если я увеличу ширину еще на один пиксель, JPanel заполнится горизонтально. То же самое касается высоты, если я расширяю JFrame по вертикали еще на один пиксель, который JPanel будет заполнять по вертикали Как на изображении ниже.

enter image description here

Единственная разница между эти два изображения - то, что я увеличил высоту / ширину JFrame еще на 1 пиксель во втором изображении

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;


class UIPanel extends JPanel {
    private BufferedImage[] textures;
    GridBagConstraints c = new GridBagConstraints();
    JLayeredPane jp = new JLayeredPane();
    BufferedImage PewterCityMap;

    UIPanel() {
        this.setLayout(new BorderLayout());
        jp.setLayout(new GridBagLayout());
        c.fill = 1;
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 1;
        c.gridheight = 1;
        try {
            PewterCityMap = ImageIO.read(new File("src/imagesUI/PewterCityMap.jpg"));
            final int width = 16;
            final int height = 16;
            final int rows = 55;
            final int cols = 53;
            textures = new BufferedImage[rows * cols];

            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    textures[(i * cols) + j] = PewterCityMap.getSubimage(
                            j * width, i * height,
                            width, height
                    );
                }
            }
        } catch (
                IOException ex) {
                  ex.printStackTrace();
        }
        int count = 0;
        for (int i = 0; i < 55; i++) {
            c.gridy = i;
            c.gridx = 0;
            for (int j = 0; j < 53; j++) {
                c.gridx = j;
                    CanEnterLbl canEnterLbl = new CanEnterLbl(new ImageIcon(textures[count]));
                    jp.add(canEnterLbl, c);
                    jp.setLayer(canEnterLbl, 0);
                count++;
            }
        }
        this.add(jp, BorderLayout.CENTER);
    }
    public static void main(String[] args) {
        JFrame jf = new JFrame();
        jf.setLayout(new BorderLayout());
        UIPanel ui = new UIPanel();
        jf.add(ui, BorderLayout.CENTER);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.pack();
        jf.setVisible(true);
    }
}

class CanEnterLbl extends JLabel{
    private Image img;
    CanEnterLbl(ImageIcon imageIcon){
        img = imageIcon.getImage();
        this.setIcon(imageIcon);
    }
    @Override
    protected void paintComponent(Graphics g){
        //In reply to @Frakcool. 
        //Firstly, thank you! Are the next two lines what you were thinking? I 
        doesn't fill correctly when using just this line though 
        //super.paintComponent(g);
        //What I was doing before
        g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
    }
}

Вот файл изображения, который я использую. Я бы использовал общедоступное изображение, но высота и ширина изображения должны быть кратны 16.
enter image description here

1 Ответ

1 голос
/ 16 апреля 2020

Мне нужно изменить размер изображения

Тогда вам не следует использовать JLabel для отображения изображения. Вам не нужны все дополнительные издержки интерфейса JLabel.

Вместо этого вы можете создать пользовательский компонент, расширив JComponent. Затем вы настраиваете метод paintComponent() для масштабирования изображения в том виде, в котором оно нарисовано.

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

Я бы предположил, что кратно 53 по горизонтали и 55 по вертикали.

Сначала GridBagLayout выделит пространство для каждого компонента в его предпочтительном размере.

Тогда, если есть дополнительное пространство, он выделит пространство для каждого компонента на основе ограничения веса x / y.

Вы не можете выделить часть пикселя для компонента. Поэтому лучшее, что можно сделать, - это выделить один пиксель, поэтому вам нужно 53 или 55 в зависимости от направления изменения размера.

Я не знаю ни одного менеджера компоновки в JDK, который мог бы предотвратить дополнительное пространство по краям панели

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

Чтобы использовать этот подход, вам понадобится главная панель, которая использует RelativeLayout по вертикали, а затем дочерние панели для каждой строки, которая использует RelativeLayout по горизонтали.

Итак, лог c может быть что-то вроде:

RelativeLayout verticalLayout = new RelativeLayout(RelativeLayout.Y_AXIS);
verticalLayout.setRoundingPolicy( RelativeLayout.EQUAL );
verticalLayout.setFill(true);
JPanel mapPanel = new JPanel( vertcalLayout );

for (int i = 0; i < rows; i++) 
{
    RelativeLayout rowLayout = new RelativeLayout(RelativeLayout.X_AXIS);
    rowLayout.setRoundingPolicy( RelativeLayout.EQUAL );
    rowLayout.setFill(true);

    JPanel row = new JPanel( rowLayout );

    for (int j = 0; j < cols; j++) 
    {
        CanEnterLbl canEnterLbl = new CanEnterLbl(…);
        row.add(canEnterLbl, new Float(1));
    }

    mapPanel.add(row, new Float(1));
}

Обратите внимание, что RelativeLayout не вычисляет начальный предпочтительный размер, поэтому вам нужно установить его так, чтобы метод frame.pack () работал правильно.

...