Advanced
Java
Services
|
Darstellen von Bildern |
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