【问题标题】:Tiny bit of extra space around the JPanel when it should fill the JFrame当 JPanel 应该填充 JFrame 时,它​​周围有一点额外的空间
【发布时间】:2020-04-16 16:35:33
【问题描述】:

我制作了一个 MRE,您可以在底部找到它,以及我正在使用的图像文件。不确定上传我的 src 文件夹是否会更好,但有人可以让我知道这样做是否可以。 首先,它确实填充了 JFrame。但是有一个问题。它仅在内容窗格尺寸为 54 的倍数时才能正确填充。我附上了一张图片,因为它更容易看到然后解释。

现在,如果我调整 JFrame 的大小。如果我将宽度再扩大一个像素,JPanel 将水平填充。如果我将 JFrame 垂直扩展一个像素,那么高度也是如此,JPanel 将垂直填充如下图。

两个图像之间的唯一区别是我在第二个图像中将 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 的倍数。

【问题讨论】:

  • 1) 不要忽略堆栈跟踪,至少要打印它们!它们为调试提供了很多有用的信息。 2) 你打破了油漆链,在paintComponent 方法上调用super.paintComponent()。它的签名是protected 而不是public
  • 谢谢。感谢trycatch 的建议。我已经更新了我的trycatch。理想的catch 应该是什么样子?我确实对我的代码(本地)进行了一些更改,以尝试将super.paintComponent(g)repaint() 一起使用,但我无法正确填写我将在一秒钟内上传我所做的事情。我感谢您的帮助!您知道为什么在调整大小时它会在侧面留下空间吗?
  • 我从来没有告诉过你将repaint() 包含在paintComponent 中,这可能会产生一个无限的小圈。
  • 谢谢!它没有填满JLabel 中的空间,所以你知道我怎样才能让它填满吗?也许将JLabels 布局设置为GridBagLayout 并设置constraint.fill = 1?类似的东西
  • 您为什么要为标签进行自定义绘画?默认情况下,JLabel 将以实际大小绘制 ImageIcon。无需自定义绘画。

标签: java image swing jframe gridbaglayout


【解决方案1】:

我需要调整图片大小

那么你不应该使用 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() 方法正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 2021-01-04
    相关资源
    最近更新 更多