我再次需要你的帮助。在下面的代码中,当我尝试向 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);
我尝试设置首选尺寸,更改图像尺寸以及更多内容在代码中解释
你的“核心”问题围绕着这里......
@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 和构建系统,因此您需要自己研究。