Advanced   Java   Services
Darstellen von Bildern
Back Next Up Home

Alte Technik (Image und paint)


Die Klasse Applet verfügt über zwei getImage()-Methoden zum Laden von Bildern. Beide Methoden stützen sich auf die getImage()-Methode des AppletContext, wie ein Blick in den Quellcode zeigt. Es werden die im Internet gängigen Formate .jpg, .gif und .png unterstützt.

Aus dem Quellcode von Applet.java

public Image getImage(URL url)
{
   return getAppletContext().getImage(url);
}

public Image getImage(URL url, String name)
{
   try
   {
      return getImage(new URL(url, name));
   }
   catch (MalformedURLException e)
   {
       return null;
   }
}

Da es in AWT keine Möglichkeit gibt, Bilder direkt darzustellen, muß die paint()-Methode überschrieben werden und eine der drawImage()-Methoden der Klasse Graphics verwendet werden. Im einfachsten Fall wie folgt.

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

Der letzte Parameter bei allen drawImage()-Methoden ist ein Objekt vom InterfaceeTyp ImageObserver. Da die Klasse Component dieses Interface implementiert, kann man hier für ein Applet immer this setzen. Man kann hier sogar bedenkenlos null setzen. Wichtig ist der ImageObserver nur für "animated gifs", hier wird die vom Interface ImageObserver geforderte Mehtode imageUpdate() gebraucht.

Bild aus dem codebase-Verzeichnis vom Server des Applets laden

Am einfachsten ist es, wenn die Bilddatei auf dem Server im selben Verzeichnis liegt wie das Applet.

import java.net.* ;
import java.awt.* ;
import java.applet.* ;

public class ImageLoadingDemo extends Applet
{
   private Image image;

   public void init()
   {
      image = getImage( getCodeBase(), "VermeerGirlReadingALetter.jpg" );
   }

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

}  // end class

Und hier sollte das Bild erscheinen...

Dieses wunderbare Gemälde stammt von dem Delfter Maler Jan Vermeer (1632 - 1675) und mit Sicherheit ist es ein Liebesbrief, den diese junge Frau liest. Aber das ist nicht unser Thema...

Bild aus einem anderen Verzeichnis vom Server des Applets laden

Die Bilddatei kann aber auch in einem anderen Verzeichnis auf dem Server liegen. Im folgenden Applet wird zum codeBase-Verzeichnis das Elternverzeichnis ermittelt und dann ein Bild vom Parallelverzeichnis img geladen.

import java.net.* ;
import java.awt.* ;
import java.applet.* ;

public class ImageLoadingDemo2 extends Applet
{
   private URL url ;
   private Image image;
   private Label label;
   private String errorMSG ;

   public void init()
   {
      try
      {
         // ermittlung des parentdirectory
         URL url = getCodeBase();
         String urlString = getCodeBase().toString() ;
         // getCodeBase liefert einen Pfad mit einem slash / am Schluß
         // gesucht wird der slash davor, denn damit endet das Parentverzeichnis
         int slashPos = urlString.lastIndexOf('/', urlString.length() -2 ) ;
         String parent = urlString.substring(0, slashPos+1) ;  // hat wieder / am schluß
         URL urlParent = new URL(parent);
         image = getImage(urlParent, "img/cezanne.apples.jpg"  );
      }
      catch(MalformedURLException ex)
      {
         errorMSG = ""+ex;
      }
      catch(java.security.AccessControlException ex)
      {
         errorMSG = ""+ex;
      }
      if(errorMSG!=null)
      {
         label = new Label(errorMSG, Label.CENTER);
         add(label);
      }
   }

   public void paint(Graphics g)
   {
      if (image!=null)
         g.drawImage(image,0,0,this);
   }
}  // end class

Dieses Stilleben mit Äpfeln stammt von Paul Cezanne (1839-1906) .

Bild von einem anderen Server laden

Aus Sicherheitsgründen ist dies für ein Applet nicht zulässig.Das folgende Applet versucht ein Java-Logo von der site "developers.sun.com" zu laden.

import java.net.* ;
import java.awt.* ;
import java.applet.* ;

public class ImageLoadingDemo3 extends Applet
{
   private Image image;
   private URL url ;
   private String errorMSG ;
   private Label label;

   public void init()
   {
      try
      {
         URL url = new URL("http://developers.sun.com/im/logo_java_home.gif");
         image = getImage(url);
         // security exception
      }
      catch(MalformedURLException ex)
      {
         errorMSG = ""+ex;
      }
      catch(java.security.AccessControlException ex)
      {
         errorMSG = ""+ex;
      }
      if(errorMSG!=null)
      {
         label = new Label(errorMSG, Label.CENTER);
         label.setBackground( new Color(240,230,220) );
         add(label);
      }
   }

   public void paint(Graphics g)
   {
      if (image!=null)
         g.drawImage(image,0,0,this);
   }
}  // end class

Und hier die Exceptionmeldung des Applets

In HTML dagegen ist dies ohne weiteres möglich. Hier wird das Logo mit dem img-Tag geladen:

<img src="http://developers.sun.com/im/logo_java_home.gif" width=103 height=80>

Die Bildgröße mit dem MediaTracker ermitteln

In der API zu getImage heißt es: "This method always returns immediately, whether or not the image exists." Das hat zur Folge, daß man die Bildgröße nicht unmittelbar nach einem getImage()-Aufruf ermitteln kann.

Image image = getImage(url);
// kehrt sofort zurück
int width = image.getWidth(this) ;
//liefert -1

Mit Hilfe des MediaTrackers kann man diese ändern. Ein Objekt dieser Klasse kann den Bildladevorgang überwachen und wartet bis die Bilddaten übermittelt worden sind.

public class ImageLoadingDemo4 extends Applet
{
   private Image image;
   private URL url ;
   private String errorMSG  ;
   private Label label;
   private int width, height;

   public void init()
   {
      image = getImage( getCodeBase(), "VermeerGirlReadingALetter.jpg" );
      trackImage(image);
   }

   private void trackImage(Image img)
   {
      try
      {
         MediaTracker mt = new MediaTracker(this) ;
         mt.addImage(img,0);
         mt.waitForAll();
         width = img.getWidth(this) ;
         height = img.getHeight(this) ;
      }
      catch(InterruptedException ex)
      {
         errorMSG = "imageloading interrupted" ;
      }
   }


Neue Technik (ImageIcon und JApplet)


Seit der Einführung der Swingklassen ist es nicht mehr notwendig, den MediaTracker selbst aufzurufen. Alle Konstruktoren (bis auf den Defaultkonstruktor, der tut garnix) der äußerst nützlichen Klasse ImageIcon rufen eine loadImage()-Methode, die den MediaTracker verwendet. Wie man sieht, teilen sich alle ImageIconObjekte ein- und denselben MadiaTracker. Dieser wiederum arbeitet mit einem unsichtbaren Objekt, einer anonymen Ableitung der Klasse Component. Die Klasse Component ist zwar abstrakt deklariert, hat aber keine einzige abstrakte Methode, daher kann man mit "new Component() {}" ein reales Objekt erzeugen !

Aus dem Quelltext der Klasse ImageIcon

protected final static Component component = new Component() {};
protected final static MediaTracker tracker = new MediaTracker(component);

protected void loadImage(Image image)
{
   synchronized(tracker)
   {
   int id = getNextID();

    tracker.addImage(image, id);
    try
    {
         tracker.waitForID(id, 0);
    }
    catch (InterruptedException e)
    {
         System.out.println("INTERRUPTED while loading Image");
    }
   loadStatus = tracker.statusID(id, false);
    tracker.removeImage(image, id);

    width = image.getWidth(imageObserver);
    height = image.getHeight(imageObserver);
   }
}

Da man dem ImageIcon-Konstruktor auch eine URL übergeben kann, werden die getImage()-Methoden aus Applet überflüssig. Der einfachste Weg, mit dem MediaTracker zu einem Image zu kommen ist also der folgende:

Image image =
new ImageIcon( new URL(getCodeBase().toString() + "monet.bateau-atelier.jpg") ) .getImage() ;
// MalformedURLException muß gecatcht werden

Aber auch das ist noch zu umständlich. Wenn wir ein JApplet nehmen, brauchen wir kein ImageObjekt mehr. Das ImageIcon verwaltet ja für uns ein ImageObjekt im Hintegrund und Swingklassen wie JLabel oder JButton können direkt mit ImageIconObjekten arbeiten. Das folgende JApplet lädt Monets Bild seines MalerAteliers in einem Boot.

import java.net.* ;
import java.awt.* ;
import javax.swing.* ;

public class ImageLoadingDemo5 extends JApplet
{
   private ImageIcon imic;
   private URL url ;
   private String errorMSG ;
   private JLabel jLabel;

   public void init()
   {
      jLabel= new JLabel();
      jLabel.setHorizontalAlignment(SwingConstants.CENTER);
      jLabel.setHorizontalTextPosition(SwingConstants.CENTER);
      jLabel.setVerticalTextPosition(SwingConstants.BOTTOM);

      getContentPane().add(jLabel);

      try
      {
         imic =
         new ImageIcon( new URL(getCodeBase().toString() + "monet.bateau-atelier.jpg") ) ;
         jLabel.setIcon(imic);
         jLabel.setText
         ("Monet's BootAtelier (" + imic.getIconWidth()+"x"+ imic.getIconHeight()+")" );
         jLabel.setToolTipText("<html><body bgcolor=#dcdcbe><center>+
         " Le bateau atelier  Claude Monet  1876  Oil on canvas<br>"+
         "Barnes Foundation, Merion, Pennsylvania</center></body></html>");
      }
      catch(MalformedURLException ex)
      {
         errorMSG = ""+ex;
      }
      catch(java.security.AccessControlException ex)
      {
         errorMSG = ""+ex;
      }
      if(errorMSG!=null)
      {
         jLabel.setText(errorMSG);
      }
   }
}  // end class

top Back Next Up Home