JPanel应该填满JFrame时,多余的多余空间

问题描述 投票:0回答:1

我制作了一个MRE,您可以在底部找到它,以及我正在使用的图像文件。不知道仅上传我的src文件夹是否会更好,但是有人可以告诉我是否可以这样做。首先,它确实填充了JFrame。但是有一个陷阱。仅在contentpane尺寸为(我相信是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

java image swing jframe gridbaglayout
1个回答
0
投票

我需要调整图像大小

然后,您不应使用JLabel显示图像。您不需要JLabel UI的所有额外开销。

相反,您可以通过扩展JComponent来创建自定义组件。然后,您可以自定义paintComponent()方法以缩放绘制时的图像。

[仅在内容窗格尺寸为,我认为是54的倍数时,才能正确填充。

我猜水平方向为53的倍数,垂直方向为55的倍数。

GridBagLayout将首先以其首选大小为每个组件分配空间。

然后,如果有多余的空间,它将根据weightx / y约束为每个组件分配空间。

您无法将像素的一小部分分配给一个组件。因此,最好的办法是分配一个像素,这就是为什么根据大小方向需要53或55的原因。

我不知道JDK中的任何布局管理器都可以防止面板边缘周围的多余空间

一种可能的解决方案是使用Relative LayoutRelative Layout允许相对于可用空间调整组件的大小。给定组件的相对大小后,您可以指定应如何分配“额外”像素。

要使用此方法,您需要一个垂直使用RelativeLayout的主面板,然后是水平使用RelativeLayout的每一行的子面板。

所以逻辑可能类似于:

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()方法可以正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.