如果你对eclipse中加载图片不太熟悉的话,恭喜你,看到了这篇文章。
问题:图片加载报错
这个问题其实很简单,因为jar包其实是一种压缩形式,你并不能通过File
直接从中读到信息。
解决方案:使用InputStream
//创建马里奥图片的inputstream对象
InputStream ma = this.getClass().getResourceAsStream("/mario_g.png");
//创建路易吉图片的inputstream对象
InputStream lu = this.getClass().getResourceAsStream("/luigi_g.png");
//使用ImageIO.read()方法直接读取成BufferedImage对象
BufferedImage marioBufferedImage = ImageIO.read(ma);
BufferedImage luigiBufferedImage = ImageIO.read(lu);
//如果你需要的是Image对象的话,只需要强转一下就行了。这里使用BufferedImage因为他可以比较方便的改变图片的大小。
Image marioImage = (Image)marioBufferedImage;
上面使用的路径,为src的相对路径。
提升:这样写为什么可以?
我们这个this.getClass().getResourceAsStream
显然是从.class文件所在目录中获取文件的,为什么我前面说只要写src的相对路径就行呢?
首先,我们需要明白的是,eclipse在编译的时候,会将src目录下的文件和.java文件一并编译到bin目录下保持不变,而.java文件则被编译成了.class文件。
这样你是不是明白了?咱们获取的的确不是src下的文件,但是bin下的确也有这个文件就是了。
你现在是不是想着把图片放到bin目录下,是不是少放在src下一次,还要更精简一些呢?
然而并不是,首先,你本次运行还是没问题的,因为你bin目录下的确有你放入的文件。但是,只要你修改了java代码,eclipse一重新编译class文件,哼哼,你src目录下没有的,bin目录下也就木大木大啦!而且你这样的话导出成jar包的时候里面会没有你的资源文件。。。
那么这里再稍微讲下如何导出jar包吧,右键项目 -> Java -> JAR file -> Next -> 在 Select the export destination 下点 Browse.. 选一个路径 -> finish
这样你就可以得到一个jar包了,里边只有编译好的class文件嘛,所以相对应的路径,就应该取class文件所在的路径咯,这也是你jar包文件取不到的原因。
言归正传,你可能会想,取class文件所在路径,用this.getClass().getResource("/").getFile()
不行吗?然后用得到的字符串,去新建一个File
对象,也是在bin里取图片啊,为啥不行?
这就要涉及到读取文件的方式了,InputStream
读取方式,是将图片转换成流数据来读取,就好像是文件肚子里的蛔虫。而File
的读取方式是先找到文件,再读取,就好像是侦探通过线索来找你。而导出成jar包侦探就找不到你了吗?还真找不到了!因为前面也说了,jar包是一种压缩文件的形式,他是一个文件,不是一个路径,就好像你藏在了一个人的梦里,而侦探又不是什么神仙,怎么可能从别人的梦里找到你?这个解答满意否?
下面再顺便讲讲使用jar包吧,很简单,在项目下新建一个lib
目录,然后把你生成的jar包拖进去,右键它,点Build Path -> Add To Build Path
就行了,你就可以创建jar包里的类的对象来使用它的方法了。
展示:这里展示下我做的jar包(一个简单的过场动画)
源码:java代码及图片
这是创建jar包前的源码,创建jar包的时候可以把public class
去掉。
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class GuoChangTest extends JFrame{
public GuoChangTest(String title) throws IOException, InterruptedException, URISyntaxException
{
JFrame jf = new JFrame(title);
Container conn = jf.getContentPane(); //得到窗口的容器
DrawGuoChang guochang = new DrawGuoChang(790,580);
conn.add(guochang);
jf.setBounds(300,80,800,600); //设置窗口的属性 窗口位置以及窗口的大小
jf.setVisible(true);//设置窗口可见
jf.setDefaultCloseOperation(DISPOSE_ON_CLOSE); //设置关闭方式 如果不设置的话 似乎关闭窗口之后不会退出程序
guochang.run();
}
public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException {
new GuoChangTest("过场动画测试"); //创建窗口
}
}
@SuppressWarnings("serial")
class DrawGuoChang extends JPanel{
private int width;
private Image marioImage;
private Image luigiImage;
private int imgWidth;
private int imgHeight;
private int t;
public DrawGuoChang(int width,int height) throws IOException, URISyntaxException {
this.width = width;
InputStream ma = this.getClass().getResourceAsStream("/mario_g.png");
InputStream lu = this.getClass().getResourceAsStream("/luigi_g.png");
BufferedImage marioBufferedImage = ImageIO.read(ma);
BufferedImage luigiBufferedImage = ImageIO.read(lu);
imgHeight = height/6;
double scale = imgHeight/(double)marioBufferedImage.getHeight();
imgWidth = (int) (marioBufferedImage.getWidth()*scale);
this.marioImage = marioBufferedImage.getScaledInstance((int) imgWidth, imgHeight, Image.SCALE_DEFAULT);
this.luigiImage = luigiBufferedImage.getScaledInstance((int) imgWidth, imgHeight, Image.SCALE_DEFAULT);
}
public void run() throws InterruptedException {
t=0;
while(true) {
t++;
Thread.sleep(20);
super.repaint();
if(t==-1) {
return;
}
}
}
protected void paintComponent(Graphics g) {
int xm,xl=1;
for(int i=0;i<3;++i) {
if(t>=0) {
xm=-100-imgWidth+t*10;
xl=100+width-t*10;
}else {
xm=-100-imgWidth;
xl=100+width;
}
g.drawImage(marioImage, xm, imgHeight*i*2, null);
g.drawImage(luigiImage, xl, imgHeight*i*2+imgHeight, null);
}
if(xl<=0) {
t=-40;
}
}
}
图片是我自己网上找的图片然后ps做的。
mario_g.png
luigi_g.png