Java 为什么显示图像的代码会给出一个"&引用;“错误”&引用;何时构建到jar中?
我想通过在JLabel中绘制BuffereImage来显示图像 x/yOffset是在JLabel的中间绘制一个较小的图像 如果我在IDE中运行代码,它可以正常工作,并在JFrame上显示图像 如果我现在将该类构建到一个jar文件中,它将不再工作 我尝试将图像设置为JLabel的图标,而不使用BuffereImage,但这不是我想要做的 下面是我的图像类的代码:Java 为什么显示图像的代码会给出一个"&引用;“错误”&引用;何时构建到jar中?,java,image,jar,bufferedimage,embedded-resource,Java,Image,Jar,Bufferedimage,Embedded Resource,我想通过在JLabel中绘制BuffereImage来显示图像 x/yOffset是在JLabel的中间绘制一个较小的图像 如果我在IDE中运行代码,它可以正常工作,并在JFrame上显示图像 如果我现在将该类构建到一个jar文件中,它将不再工作 我尝试将图像设置为JLabel的图标,而不使用BuffereImage,但这不是我想要做的 下面是我的图像类的代码: public class ImageHQ extends JLabel { BufferedImage img; int xOff
public class ImageHQ extends JLabel {
BufferedImage img;
int xOffset=0;
int yOffset=0;
public ImageHQ(String path, int xOffset, int yOffset) {
try {
try {
img = ImageIO.read(new File(getClass().getResource(path).toURI()));
} catch (URISyntaxException ex) {
Logger.getLogger(ImageHQ.class.getName()).log(Level.SEVERE, null, ex);
errorMsg(ex.getMessage());
}
} catch (IOException ex) {
Logger.getLogger(ImageHQ.class.getName()).log(Level.SEVERE, null, ex);
errorMsg(ex.getMessage());
}
this.xOffset = xOffset;
this.yOffset = yOffset;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(img, 0+xOffset, 0+yOffset, null);
repaint();
}
public void errorMsg(String msg) {
JOptionPane.showMessageDialog(null, msg, "Fehler", JOptionPane.ERROR_MESSAGE);
}
}
PS:errorMsg方法也不会给我错误。问题在于:
new File(getClass().getResource(path).toURI())
应用程序资源不能保证是单独的文件。jar条目只是压缩存档的一部分。它不是硬盘上的单独文件。这就是为什么不能使用文件来读取它
读取资源的正确方法是根本不尝试将其转换为文件getResource
返回一个URL;您可以直接将该URL传递给:
请注意使用了类文本,ImageHQ.class
,而不是getClass()。这保证了您的资源是相对于您自己的类来读取的,而不是一个子类,它可能位于不同的包或不同的包中
从输入流读取
一般来说,可能存在URL不够的情况。您还可以使用获取从资源读取的开放InputStream。在您的情况下,您可以:
try (InputStream stream = ImageHQ.class.getResource(path)) {
img = ImageIO.read(stream);
}
但这将是次优的,因为URL可以提供InputStream无法提供的信息,如文件名、内容类型,以及图像数据长度的预先知识
资源路径
传递给getResource
和getResourceAsStream
的字符串参数实际上不是文件名。它是相对URL的路径部分。这意味着以C:\开头的参数将始终失败
因为参数是URL,所以在所有平台上,它总是使用前斜杠(/
)来分隔路径组件。通常,它是针对调用其getResource*方法的类对象的包进行解析的;因此,如果ImageHQ
在com.example
包中,则此代码:
ImageHQ.class.getResource("logo.png")
将在.jar文件中查找com/example/logo.png
您可以选择以斜杠开始字符串参数,这将强制它相对于.jar文件的根。上述内容可以写成:
ImageHQ.class.getResource("/com/example/logo.png")
ClassLoader中也有getResource*方法,但不应使用这些方法。始终使用Class.getResource或Class.getResourceAsStream。ClassLoader方法在Java 8和更早版本中的功能类似,但在Java 9中,Class.getResource在模块化程序中更安全,因为它不会与模块封装冲突。(ClassLoader.getResource不允许在其字符串参数的开头使用/
,并且始终假定该参数相对于.jar文件的根。)
空返回值
如果path参数没有命名.jar文件中实际存在的资源(或者资源位于不允许读取的模块中),则所有getResource*方法都将返回null
。NullPointerException或IllegalArgumentException是这种情况的常见症状。例如,如果没有logo.png
与.jar文件中的ImageHQ类在同一个包中,则getResource将返回null,并将该null传递给ImageIO.read
将导致IllegalArgumentException,如ImageIO.read文档中所述
如果出现这种情况,可以通过列出.jar文件的内容来对其进行故障排除。有很多方法可以做到这一点:
- 每个IDE的文件浏览器或文件树都可以检查.jar文件的内容
- 如果您的JDK位于shell的路径中,那么只需执行
jartf/Path/to/myapplication.jar
- 在Unix和Linux中,
也可以工作,因为.jar文件实际上是一个包含一些特定于Java的条目的zip文件unzip-v/path/to/myapplication.jar
- 在Windows中,您可以创建.jar文件的副本,将副本的扩展名更改为.zip,并使用任何zip工具(包括Windows文件资源管理器)打开它
com.example
包中,并且您的代码正在执行ImageHQ.class.getResource(“logo.png”)
,那么您将检查.jar文件的内容,以查找com/example/logo.png
条目。如果不存在,getResource方法将返回null
关于打印错误消息
将ex.getMessage()
替换为ex.toString()
。通常情况下,异常消息本身没有意义。您还应该添加ex.printStackTrace()
到每个catch
块(或添加记录堆栈跟踪的日志语句),这样您就可以确切地知道问题发生的位置
关于绘画
切勿从paintComponent方法调用
repaint()
。这将创建一个无限循环,因为repaint()
将强制Swing绘制系统再次调用paintComponent
。整个自定义组件是不必要的。抗锯齿渲染提示对图像没有任何影响,它们与文本和绘制的线条等相关。可以使用EmptyBorder
实现偏移。还请注意(当实际需要自定义绘制图像时),每个JComponent
都是ImageObserver
sog.drawImage(…null)
最好是g.drawImage(…这个)代码>。至于反对票,我同意这是令人迷惑的。也可能是投票结束的人(原因对我来说同样神秘),但谁能肯定呢?忽略我所说的“不必要的”。我只看了代码,没有看描述,在那里你记录了更多的东西
ImageHQ.class.getResource("/com/example/logo.png")