The ImageObserver Interface

It is sometimes said, only half in jest, that WWW stands for “World Wide Wait”, primarily because of the amount of time it takes for graphics-heavy pages to load. Although reading large files off a hard drive can be time-consuming, most users have trained themselves not to notice the time it takes; file loading seems to happen instantaneously. However, this is not the case when files are loaded from a network, particularly when that network is the Internet. It is not uncommon for even small images to take several minutes to load. Since Java loads images in a different thread than the main execution of a program, a program can do something while the pictures are downloaded. However, programs don’t get impatient; users do. It is a good idea to keeps users informed about how much of an image has been loaded and how much longer they can expect to wait. The java.awt.image.ImageObserver interface allows you to monitor the loading process so that you can keep the user informed and use the image as quickly as possible once it does load.

When discussing getImage( ), I said that the method returned immediately, before downloading the image. Downloading begins when you try to display the image or do something else that forces loading to start (for example, passing the Image object to the prepareImage( ) method of java.awt.Component). Because loading takes place in a separate thread, programs don’t have to spin their wheels while lots of pictures are downloaded; they can continue doing something useful, even if that’s limited to keeping the user informed. However, loading an image asynchronously creates a new problem: how do you know when it’s ready? An Image object exists as soon as getImage( ) returns, long before anything is known about the image it represents. You can call an Image’s methods before it has finished loading, but the results are rarely what you want or expect. For example, the getWidth( ) and getHeight( ) methods return -1 until enough data has been loaded for these values to be known.

The ImageObserver interface allows an object to monitor the progress of loading and to take action (such as drawing the Image) when the Image is ready for use. You can also use ImageObserver objects to track the progress of an image that is being created from scratch, using java.awt.image.MemoryImageSource or some other instance of the java.awt.image.ImageProducer interface. This interface consists of a group of constants and a single method, imageUpdate( ):

public boolean imageUpdate(Image image, int infoflags, int x, int y, 
 int width, int height)

java.awt.Component implements ImageObserver, so all its subclasses (including java.applet.Applet, java.awt.Canvas, java.awt.Panel, javax.swing.JButton, and many more) do as well.

If you’ve done much programming in Java, you’ve probably used the ImageObserver class without thinking about it: the this that you stick at the end of a call to drawImage( ) says to use the current component as an ImageObserver:

g.drawImage(theImage, 0, 0, this);

If the image is complete, then it’s drawn and that’s that. On the other hand, if the image is not ready, then the component’s imageUpdate( ) method will be called periodically, giving it the chance to check the status of the image and respond accordingly. Other methods that take ImageObserver objects as arguments include the getWidth( ) , getHeight( ), and getProperty( ) methods of java.awt.Image; the checkImage( ) and prepareImage( ) methods of java.awt.Component; and the setImageObserver( ) method of javax.swing.ImageIcon. Passing an ImageObserver to any of these methods signals that the object is interested in the image and should be notified through the imageUpdate( ) method when the image’s status changes. Variables that are set using a method such as getWidth( ) or getHeight( ), and pictures that are drawn on the screen using drawImage( ), are not updated automatically when imageUpdate( ) is called. It’s your job to update them when the image changes.

If you want to create your own ImageObserver, you first create a subclass of any Component or create your own class that implements the ImageObserver interface. Be sure to import java.awt.image.ImageObserver or java.awt.image.* Importing java.awt.* does not automatically import java.awt.image.ImageObserver. Your new class, or your Component subclass, must include an imageUpdate( ) method. As you’ll see in the next section, there are a series of tests that imageUpdate( ) can perform to determine the current status of the image.

Example 9.6 is an applet that loads an image from the Net. It supplies its own imageUpdate( ) method (overriding the imageUpdate( ) method Applet inherits from Component) to see whether the image has loaded. Until the image has finished loading, the applet displays the words “Loading Picture. Please hang on”. Once the image has fully loaded, the applet displays it.

Example 9-6. Load an Image

import java.awt.*;
import java.applet.*;
import java.awt.image.*;

public class DelayedImageView extends Applet {

  private Image picture;
  
  public void init(  ) {
    this.picture = this.getImage(this.getDocumentBase(  ), "cup.gif");
  }
  
  public void paint(Graphics g) {  
    
    if(!g.drawImage(this.picture, 0, 0, this)) {
      g.drawString("Loading Picture. Please hang on", 25, 50);
    }
     
  }
  
 public boolean imageUpdate(Image image, int infoflags, int x, int y, 
  int width, int height) {
  
    if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
      this.repaint(  );
      return false;
    }
    else {
      return true;
    }
  
  } 
  
}

There are a couple of things to note about this example. First, the drawImage( ) method returns a boolean. Many programmers don’t realize this, since the return value of drawImage( ) is often ignored. However, that boolean tells you whether the image was drawn successfully. If it was, drawImage( ) returns true. Otherwise, drawImage( ) returns false.

Second, the imageUpdate( ) method is called by the ImageObserver when necessary; you do not call it explicitly. It returns false if the image is complete and no longer needs to be updated. It returns true if the image still needs to be updated.

Tip

Let’s repeat that point, since it’s easy to get backwards. The imageUpdate( ) method should return false if the image is complete and true if the image is not complete. The imageUpdate( ) method answers the question “Does this image need to be updated?” It does not answer the question “Is this image complete?”

Now, let’s look at what imageUpdate( ) does. The Image being loaded is passed into imageUpdate( ) through the image argument. Various mnemonic constants are combined to form the infoflags argument, which indicates what information about the image is now available. For instance, ImageObserver.ALLBITS is 32, and means that the Image is complete. You test whether the ALLBITS flag is set in infoflags by logically and ing it with the mnemonic constant ImageObserver.ALLBITS and then seeing if the result is equal to ImageObserver.ALLBITS. This chunk of Boolean algebra looks complicated but is more efficient than the alternatives.

The precise meaning of the x, y, width, and height arguments depends on the contents of the infoflags argument. The flags used in this argument are described in the next section.

The imageUpdate( ) method needs to do three things:

  1. Check to see what has changed in this Image, using infoflags.

  2. Perform any action needed to update the state of the running program.

  3. Return true if further updates are needed and false if all necessary information is available.

The ImageObserver Constants

The ImageObserver interface defines eight mnemonic constants, which are used as flags to report the image’s status in calls to imageUpdate( ). Table 9.1 lists the constants and their meanings.

Table 9-1. ImageObserver Constants

Flag

Meaning If the Flag Is Set

ImageObserver.WIDTH

The width of the image is available in the width argument to imageUpdate( ). Until this flag is set, getWidth( ) returns -1.

ImageObserver.HEIGHT

The height of the image is available in the height argument to imageUpdate( ). Until this flag is set, calls to getHeight( ) return -1.

ImageObserver.PROPERTIES

The properties of the image are now available and can be accessed with the getProperty( ) method of the Image object.

ImageObserver.SOMEBITS

Some portion of the data needed to draw the image has been delivered. The bounding box of the available pixels is given by the x, y, width, and height arguments to the imageUpdate( ) method.

ImageObserver.FRAMEBITS

Another complete frame of a multiframe image is now available. The x, y, width, and height arguments to imageUpdate( ) have no meaning.

ImageObserver.ALLBITS

The image is now complete. The x, y, width, and height arguments to imageUpdate( ) have no meaning. At this point, the imageUpdate( ) method should return false, to indicate that the image requires no further monitoring.

ImageObserver.ERROR

The image encountered an error while loading. No further information will be forthcoming, and attempts to draw the image will fail. The ImageObserver.ABORT flag is set at the same time to indicate that image loading was aborted.

ImageObserver.ABORT

Loading aborted before the image was complete. No more information will become available without further action to reload the Image. If the ImageObserver.ERROR bit is not also set in infoflags, then attempting to access any of the data in the image restarts the loading process.

For example, to test whether the width and the height of the image are known, you would put the following code in the imageUpdate( ) method:

if ((infoflags & ImageObserver.WIDTH) == ImageObserver.WIDTH  &&
  (infoflags & ImageObserver.HEIGHT) == ImageObserver.HEIGHT) {...}

The difference between the ImageObserver.ERROR and ImageObserver.ABORT flags can be confusing. You would get an ImageObserver.ERROR if the image data was incorrect—for example, you tried to download a mangled file. If you try to load the image again, you’ll get the same bad data. ImageObserver.ABORT usually indicates some kind of network error, such as a timeout; if you try to load the image again, you might succeed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.64.128