javaGUI学习10:AWT-加载和显示图像1

1、Image类与image包

Image抽象类,定义的方法提供对图像信息的访问。而创建和处理图像的基本机构则在image包里。

  • java.awt.Image的引用被传递给用来显示和处理图像的其他AWT对象的方法,例如:drawImage(Image,int,int,ImageObserver):用来将图片显示在构件中。
  • 在java.awt . image软件包中,几乎所有的类都和生产或消费图像有关。图像生产者为产生图像的位,而图像消费者接受图像的位。
  • 在java.awt . image软件包中,ImageProducer和 ImageConsumer接口都被实现两次:像素抓取器图像过滤器属于消费者,而被过滤的内存的图像源则是生产者。
  • java . awt . Image类为图像提供引用,而java.awt . image软件包实际从事与生产图像有关的工作。

Image方法:

void flush() //刷新此Image对象使用的所有可重构资源。  
float getAccelerationPriority() //返回加速优先级提示的当前值。  
ImageCapabilities getCapabilities(GraphicsConfiguration gc) //返回一个ImageCapabilities对象,可以在指定的GraphicsConfiguration上查询此Image的功能。  
abstract Graphics getGraphics() //创建用于绘制到屏幕外图像的图形上下文。  
abstract int getHeight(ImageObserver observer) //确定图像的高度。  
abstract Object getProperty(String name, ImageObserver observer) //按名称获取此图像的属性。  
Image getScaledInstance(int width, int height, int hints) //创建此图像的缩放版本。  
abstract ImageProducer getSource() //获取生成图像像素的对象。  
abstract int getWidth(ImageObserver observer) //确定图像的宽度。  
void setAccelerationPriority(float priority) //为此图像设置有关加速度有多重要的提示。 

getWidth与getHeight返回的高度和宽度都是在图像完全被加载后才有效的

getSourse的意义是为了过滤该图像

图像都有一个与之关联的Graphics,对图像进行画面外缓冲

Graphics提供的重载的drawImage方法,可以将缩放后的图像画出来

flush刷新图像使用的所有资源,包括高速缓存的图像像素和系统资源,图像被完全重构的时,刷新图像是一个必须的过程

2、图像的生产者与图像的消费者

AWT中,许多图像操作都是异步进行的。例如,如果在调用的同时没有加载图像,drawImage ()什么也画不出来,而只是产生与图像相关的位。

g.drawlmage ( image,o,o,this) ;
  • 这么做的作用仅仅只是不想让你必须加载整个图像。
  • 当图像生产者加载图像时,图像观察者可以监视其进展情况。AWT构件就是一类图像观察者,当它们发现图像被完全加载时,它们重绘制它们自身。所以调用drawImage ()寄存器中的 this构件作为观察者。
  • 当图像完全加载时,该构件被重绘制,paint ()方法被调用,再次调用drawlmage ()方法来绘制图像中所有的位。
  • 在AWT中,要想了解图像操作,要了解异步以及ImageProducer和ImageObserver之间的关系。
2.1 ImageProducer

图像相关联的位不在java.awt.Image中,但每个图像都维护一个和ImageProducer的关联。

她的作用是生产图像的位并将他们传递给ImageConsumer。

图像生产者生产位。

2.2 ImageObserver

该接口中定义了一个常数集合和一个方法。

方法:

public voolean imageUpdate(Image img,int flags, int x, int y, int width, int height);

flags的作用是通知图像观察者图像象生产的进展。下面的表中的常数代表传递给imageUpdate的flags参数中的位

标志 含义
ABORT 图像加载被中断
ALLBITS 所有的位都已经加载给图像
ERROR 在加载过程中发生错误
FRAMEBITS 多帧图像的一个帧传送,一般用于动画GIF
HEIGHT 图像的高度已经可用
PROPERTIES 图像的属性已经可用
SOMEBITS 图像的缩放变倜的多个位已可用
WIDTH 图像的宽度已经可用

ImageObserver 的实现普遍存在于AWT中,这是因为java.awt.Component 实现 ImageObserver。所以,每个构件都是ImageObserver,当一个给定的 ImageProducer 采取异步操作时,这个Ima-geObserver可以选择是否被更新。

ps:所有的构件都是图像观察者,所以任何构件都可以被传递到要获取ImageObserver参数的方法中。

3、加载和显示图像
import java.applet.Applet;
import java.awt.*;
import java.net.URL;

public class demo06 extends Applet {
    Image image;

    @Override
    public void init() {
        URL codeBase = getCodeBase();//这个applet位置的URL
        System.out.println(codeBase);
        image = getImage(codeBase,"1.jpg");//返回对图像的引用,为了阐明加载图像的异步行为,图像的宽度和高度在getImage()返回后立即被显示出来
		System.Out.print(image.getWidth(this));
        System.Out.print(image.getHeight(this));
    }

    public void paint(Graphics g){
        g.drawImage(image,0,0,this);
    }
}

显示图像的宽度和高度都只是临时值,尽管这时getImage已经返回对图像的引用,但定义图像的位还没有被加载。Image相关的图像位在需要之前不被生产。所以在图像完全加载前,getWidth和getHeight都是-1。

4、异步的图像加载和绘制

下面解释上面程序现象的原因:

  • 传递到Graphics.drawImage ()中的第三个参数指明了图像观察者。在上面所举的例子中,第三个参数是this,也就是说图像观察者是this,这意味着观察者是 applet自身。由于java.applet .Applet扩展了java.awt.Component,而且Component实现 ImageObserver,所以所有的 applet都具有真正的图像观察者的资格。
  • drawImage ()在第一次被调用时,没有任何图像被加载。所以也就没有图像位可绘制,drawImage ()仅仅向和图像相关的图像生产者注册图像观察者(在本例中,是applet自身)。所以当调用返回时,什么也没有绘制。
  • 在调用drawImage ()返回之后,只要有图像的新的部分被加载,图像观察者中的imageUpdate ()就会被调用。因为上面的 applet 程序范例中没有覆盖imageUpdate(),所以只要有新的图像位被加载,图像生产者就会调用通过继承得到的Component . imageUpdate()。
  • 当处理批量新加载的图像位时,Component.imageUpdate ()方法调用repaint (),结果是调用paint ()。当然,这个applet中的paint ()方法调用drawImage (),绘制和刚才得到图像位一样多的图像。

上面所讲的方法一直被循环调用,直到图像被完全加载:图像生产者加载图像的部分并调用图像观察者中的imageUpdate ()。当图像观察者是AWT构件时,Component . imageUpdate ()调用repaint ()方法清除构件背景并调用paint ()。在上面列举出的程序范例中,applet 的 paint()调用drawImage ()方法绘制出刚刚得到的图像位。重复循环,图像生产者加载图像的下—块,调用图像观察者的imageUpdate ()。当图像被完全加载时,图像生产者停止调用观察者imageUpdate (),循环中断。

public void paint(Graphics g){
   g.drawImage(image,0,0,this);
   System.out.println(image.getWidth(this) + "后"); //加载完图像后,正确打印宽度
}
5、applet和应用程序的区别

​ applet 获取图像提供内部支持,也就是Applet. getImage方法。而对于Java应用程序来讲,没有扩展applet,所以应用程序实现合并图像时,不同于 applet。

  • 在ImageTestApplication构造器中,应用程序获取图像的引用。应用程序从Toolkit类中调用getImage ()方法,而不是调用Applet . getImage ()方法。

  • 首先,调用Toolkit类中的static getDefaultToolkit()方法,为返回应用程序运行的平台默认的工具包。然后,调用工具包中的getImage方法,该方法返回java.awt. Image的引用。在这里要注意的是 Toolkit.getImage()被重载,来获取URL或String参数。

  • applet和应用程序之间的另一个区别是:应用程序的显示位置必须被考虑。如果图像已经在(0,0)处被画出,就像在程序范例5-1所给出的applet 代码一样,图像的顶部将被绘制在框架标题条的下面。applet 的左上角位于applet菜单条的下面,而应用程序的左上角则是位于其框架的顶端。

  • 注意,addNotify ()被覆盖以得到框架的空白区的引用,其目的是为了设置框架的边框。在框架的同位体被创建之前,getInsets ()一直返回值为(0,0,0,0)的空白区。同位体由addNotify ()创建,所以调用getInsets ()方法必须在其框架对应的同位体被创建之后。请参见11.8节“构件和同位体”中的相关内容,可以得到更多的关于同位体和覆盖addNotify ()的信息。

  • 最后,图像的尺寸大小是硬编码进应用程序的,这种方法明确地不被推荐实行:

    setBounds(100,100,217 + insets.left, 321 + insets.top);
    
6、等待图像加载

​ 所有的applet程序和应用程序实现加载和显示图像都是采用从图像的顶部到底部的方式进行的,这是由于图像加载的异步所导致的。一个比较美观、令人满意的方法是在图像显示之前等待图像完全加载。有很多的途径可以用来实现该效果,其中的一个途径就是使用imageUpdate()方法,使用该方法可以获得加载图像的进展状况。

7、一次绘制图像的一行扫描线

重写imageUpdate()方法,在imageUpdate()中调用repaint()方法

 @Override
    public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
        System.out.println(h);
        repaint();

        if((infoflags & ALLBITS) == 0) {
            return true;
        }else {
            return false;
        }
    }

但这样会引起闪动,消除闪动:重写update方法。因为调用repaint(),update()会被触发调用,但在缺省模式下update会先清除构件中所有的背景,在调用构件中的paint方法。

public void update(Graphics g){
    paint(g);
}
8、MediaTracker

与图像的异步加载相比,这个类提供了一个比较方便的方法,可以跟踪图像的加载。

使用MediaTracker分为下面的三步:

1)创建MediaTracker实例。

2)使用 MediaTracker . addImage ()指明要跟踪的图像对象。

3)创建try/catch 块。try 块等待和ID相关的图像完全加载。

由于MediaTracker 的 waitForID方法可能抛出InterruptedException,所以实现catch块是必要的。
如果你希望在显示图像之前,先将图像完全加载,可以使用MediaTracker。使用MediaTracker意味着你不必覆盖imageUpdate ()方法,而且不必通过将变量flags和正确的常量求与来判断什么时候图像被完全加载。

public static void waitForImage(Component component, Image image){
	MediaTrachker tracker = new Mediatracker(component);
    tracker.addImage(image,0);
    tracker.waitForID(0);
}

你可能感兴趣的:(#,javaGUI,java)