图像溢出 JPanel 中分配的空间:寻求帮助

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

我再次需要你的帮助。在下面的代码中,当我尝试向 JPanel 添加图像时,它完全忽略了

GridBagLayout
GridBagConstraints
分配的空间。事实上,图像占据了它所能占据的所有空间,而不受任何限制。我认为问题源于图像太大(5000px * 3333px),但它应该限制在分配的空间内。谢谢您的协助。

代码就在这里:

public class RProfile extends JPanel {
    private Membre membre;
    private RLine lineH;

    public RProfile(Membre user){
        this.membre = user;
        setBackground(new Color(5, 14, 26));
        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.gridheight = 1;
        gbc.fill = BOTH;
        gbc.anchor = WEST;
        gbc.weightx = 16.9;
        gbc.weighty = 1;
        gbc.insets = new Insets(0,0,0,0);
        add(new RMembre(user), gbc);

        gbc.gridx = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.anchor = GridBagConstraints.NORTH;
        gbc.weightx = 0;
        gbc.weighty = 1;
        gbc.insets = new Insets(0,0,0,0);
        lineH = new RLine(0, 0, 3, 1000, new Color(0, 71, 79)); // Updated endX to 0
        add(lineH, gbc);

        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.gridheight = 1;
        gbc.fill = BOTH;
        gbc.anchor = CENTER;
        gbc.weightx = 100;
        gbc.weighty = 1;
        ImageIcon photoIcon = new ImageIcon("./res/img/faction/Alliance.png");
        JLabel photoLabel = new JLabel(photoIcon);
        add(photoLabel, gbc);
    }

    public void linePreferedSize(int lh){
        lineH.setPreferredSize(new Dimension(THICKNESS, lh));
    }
}

我也尝试使用 Buffered 创建自己的类,但没有解决我的问题:

package fr.riya.entity.graphic;

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

public class RImage extends JPanel {

     private BufferedImage cardImage;

    public RImage() {
        try {
            cardImage = ImageIO.read(new File("./res/img/space/04.jpg"));
        } catch (IOException ex) {
            System.out.println("Exception trying to load image file.");
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredSize();
    }

    @Override
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawImage(cardImage, 0, 0, this);
    }
}
gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.gridheight = 1;
        gbc.fill = NONE;
        gbc.anchor = CENTER;
        gbc.weightx = 0;
        gbc.weighty = 0;
        RImage rImage = new RImage();
        rImage.setPreferredSize(new Dimension(500, 500));
        add(rImage, gbc);

我尝试设置首选尺寸,更改图像尺寸以及更多内容在代码中解释

java image swing gridbaglayout
1个回答
0
投票

你的“核心”问题围绕着这里......

@Override
public Dimension getPreferredSize() {
    return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredSize();
}

@Override
public Dimension getMinimumSize() {
    return getPreferredSize();
}

就我个人而言,我会小心搞乱

minimumSize
,或者至少会考虑一些替代方案,但这就是我。

“真正”的问题是,如果您尝试调用

setPreferredSize
,该设置将被忽略,因为您已经覆盖了
getPreferredSize
方法。

那么,答案是什么?嗯,很复杂。

您要做的第一件事是修改

getPreferredSize
方法来检查
preferredSize
是否已设置。如果有,则返回其值,否则,执行您的自定义逻辑。

@Override
public Dimension getPreferredSize() {
    if (isPreferredSizeSet()) {
        return super.getPreferredSize();
    }
    return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredSize();
}

接下来的部分比较困难。现在,您需要决定在可用空间较小时如何处理图像。您是否将图像调整或填充到可用空间?您还应该注意,Java 的默认扩展工作流程往往会针对速度而不是质量进行优化。

请参阅 调整大小后的图像质量非常低 - Java 了解更多示例。

现在有了这个,我们可以创建一个简单的、可重复使用的组件,可用于设置它的

preferredSize
,并根据
scaleType
设置,将缩放后的图像适合或填充到可用空间。

nb:这是基于 将 ImageIcon 自动缩放到标签大小

徽章图像最初为 246x304,背景为 3840x2160。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame("Test");
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    protected class TestPane extends JPanel {

        public TestPane() throws IOException {
            setLayout(new GridBagLayout());

            BufferedImage crest = ImageIO.read(getClass().getResource("/resources/images/Gryffindor.png"));
            BufferedImage background = ImageIO.read(getClass().getResource("/resources/images/mando01.jpg"));

            ScalablePane crestPane = new ScalablePane(crest);
            crestPane.setPreferredSize(new Dimension(100, 100));

            ScalablePane bgPane = new ScalablePane(background, ScalablePane.ScaleType.FILL);
            bgPane.setPreferredSize(new Dimension(800, 800));


            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.NORTH;
            add(crestPane, gbc);


            gbc.gridx = 1;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.gridheight = GridBagConstraints.REMAINDER;
            add(bgPane, gbc);
        }

    }

    public class ScalablePane extends JPanel {
        enum ScaleType {
            FIT, FILL
        }

        private Image master;
        private ScaleType scaleType = ScaleType.FIT;
        private Image scaled;

        public ScalablePane(Image master) {
            this(master, ScaleType.FIT);
        }

        public ScalablePane(Image master, ScaleType scaleType) {
            this.master = master;
            setScaleType(scaleType);
        }

        @Override
        public Dimension getPreferredSize() {
            if (isPreferredSizeSet()) {
                return super.getPreferredSize();
            }
            return master == null ? super.getPreferredSize() : new Dimension(master.getWidth(this), master.getHeight(this));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Image toDraw = null;
            if (scaled != null) {
                toDraw = scaled;
            } else if (master != null) {
                toDraw = master;
            }

            if (toDraw != null) {
                int x = (getWidth() - toDraw.getWidth(this)) / 2;
                int y = (getHeight() - toDraw.getHeight(this)) / 2;
                g.drawImage(toDraw, x, y, this);
            }
        }

        @Override
        public void invalidate() {
            generateScaledInstance();
            super.invalidate();
        }

        public void setScaleType(ScaleType scaleType) {
            this.scaleType = scaleType;
            repaint();
        }

        public ScaleType getScaleType() {
            return scaleType;
        }

        protected void generateScaledInstance() {
            scaled = null;
            switch (getScaleType()) {
                case FILL:
                    scaled = getScaledInstanceToFill(master, getSize());
                    break;
                case FIT:
                    scaled = getScaledInstanceToFit(master, getSize());
                    break;
            }
        }

        protected BufferedImage toBufferedImage(Image master) {
            Dimension masterSize = new Dimension(master.getWidth(this), master.getHeight(this));
            BufferedImage image = createCompatibleImage(masterSize);
            Graphics2D g2d = image.createGraphics();
            g2d.drawImage(master, 0, 0, this);
            g2d.dispose();
            return image;
        }

        public Image getScaledInstanceToFit(Image master, Dimension size) {
            Dimension masterSize = new Dimension(master.getWidth(this), master.getHeight(this));
            return getScaledInstance(
                    toBufferedImage(master),
                    getScaleFactorToFit(masterSize, size),
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR,
                    true);
        }

        public Image getScaledInstanceToFill(Image master, Dimension size) {
            Dimension masterSize = new Dimension(master.getWidth(this), master.getHeight(this));
            return getScaledInstance(
                    toBufferedImage(master),
                    getScaleFactorToFill(masterSize, size),
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR,
                    true);
        }

        public Dimension getSizeToFit(Dimension original, Dimension toFit) {
            double factor = getScaleFactorToFit(original, toFit);
            Dimension size = new Dimension(original);
            size.width *= factor;
            size.height *= factor;
            return size;
        }

        public Dimension getSizeToFill(Dimension original, Dimension toFit) {
            double factor = getScaleFactorToFill(original, toFit);
            Dimension size = new Dimension(original);
            size.width *= factor;
            size.height *= factor;
            return size;
        }

        public double getScaleFactor(int iMasterSize, int iTargetSize) {
            return (double) iTargetSize / (double) iMasterSize;
        }

        public double getScaleFactorToFit(Dimension original, Dimension toFit) {
            double dScale = 1d;
            if (original != null && toFit != null) {
                double dScaleWidth = getScaleFactor(original.width, toFit.width);
                double dScaleHeight = getScaleFactor(original.height, toFit.height);
                dScale = Math.min(dScaleHeight, dScaleWidth);
            }
            return dScale;
        }

        public double getScaleFactorToFill(Dimension masterSize, Dimension targetSize) {
            double dScaleWidth = getScaleFactor(masterSize.width, targetSize.width);
            double dScaleHeight = getScaleFactor(masterSize.height, targetSize.height);

            return Math.max(dScaleHeight, dScaleWidth);
        }

        public BufferedImage createCompatibleImage(Dimension size) {
            return createCompatibleImage(size.width, size.height);
        }

        public BufferedImage createCompatibleImage(int width, int height) {
            GraphicsConfiguration gc = getGraphicsConfiguration();
            if (gc == null) {
                gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
            }

            BufferedImage image = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            image.coerceData(true);
            return image;
        }

        protected BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
            BufferedImage imgScale = img;
            int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
            int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);

            if (dScaleFactor <= 1.0d) {
                imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
            } else {
                imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
            }

            return imgScale;
        }

        protected BufferedImage getScaledDownInstance(
                BufferedImage img,
                int targetWidth,
                int targetHeight,
                Object hint,
                boolean higherQuality) {

            int type = (img.getTransparency() == Transparency.OPAQUE)
                    ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

            BufferedImage ret = (BufferedImage) img;

            if (targetHeight > 0 || targetWidth > 0) {
                int w, h;
                if (higherQuality) {
                    // Use multi-step technique: start with original size, then
                    // scale down in multiple passes with drawImage()
                    // until the target size is reached
                    w = img.getWidth();
                    h = img.getHeight();
                } else {
                    // Use one-step technique: scale directly from original
                    // size to target size with a single drawImage() call
                    w = targetWidth;
                    h = targetHeight;
                }

                do {
                    if (higherQuality && w > targetWidth) {
                        w /= 2;
                        if (w < targetWidth) {
                            w = targetWidth;
                        }
                    }
                    if (higherQuality && h > targetHeight) {
                        h /= 2;
                        if (h < targetHeight) {
                            h = targetHeight;
                        }
                    }

                    BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                    Graphics2D g2 = tmp.createGraphics();
                    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                    g2.drawImage(ret, 0, 0, w, h, null);
                    g2.dispose();

                    ret = tmp;
                } while (w != targetWidth || h != targetHeight);
            } else {
                ret = new BufferedImage(1, 1, type);
            }

            return ret;
        }

        protected BufferedImage getScaledUpInstance(
                BufferedImage img,
                int targetWidth,
                int targetHeight,
                Object hint,
                boolean higherQuality) {

            int type = BufferedImage.TYPE_INT_ARGB;

            BufferedImage ret = (BufferedImage) img;
            int w, h;
            if (higherQuality) {
                // Use multi-step technique: start with original size, then
                // scale down in multiple passes with drawImage()
                // until the target size is reached
                w = img.getWidth();
                h = img.getHeight();
            } else {
                // Use one-step technique: scale directly from original
                // size to target size with a single drawImage() call
                w = targetWidth;
                h = targetHeight;
            }

            do {
                if (higherQuality && w < targetWidth) {
                    w *= 2;
                    if (w > targetWidth) {
                        w = targetWidth;
                    }
                }

                if (higherQuality && h < targetHeight) {
                    h *= 2;
                    if (h > targetHeight) {
                        h = targetHeight;
                    }
                }

                BufferedImage tmp = new BufferedImage(w, h, type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();

                ret = tmp;
                tmp = null;
            } while (w != targetWidth || h != targetHeight);
            return ret;
        }
    }
}

您还应该注意,像

cardImage = ImageIO.read(new File("./res/img/space/04.jpg"));
这样的事情本质上是危险的。您往往无法控制程序可能执行的上下文,这将更改“工作目录”,这意味着您的程序将无法找到它需要的文件。

更好的解决方案是将资源“嵌入”到应用程序上下文中(这实际上会将资源打包到生成的 Jar 中),并且允许您在运行时更轻松地加载它们(请注意示例中使用

getClass().getResource(...)
),无论“工作目录”上下文如何。如何完成此操作取决于您的 IDE 和构建系统,因此您需要自己研究。

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