Grafikdateien laden und anzeigen (Java): Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K (Beispiel Linux)
K
 
(89 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Häufig möchte man aus verschiedenen Gründen Grafikdateien, wie Icons, Eyecatcher oder Fotos in Java-Programme einbinden.
+
 
Im Folgenden soll anhand von Code-Beispielen gezeigt werden, wie unter verschiedenen Bedingungen und [[GUI]]-Schnittstellen ([[AWT]]/[[Swing]]) Grafiken eingebunden werden können.<br>
+
<div style="padding:1em;font-size:1.125em;border-style:solid;border-color:#FABD23;border-width:1px;background-color:#F0F0F0;">Häufig möchte man aus verschiedenen Gründen Grafikdateien, wie Bilder und Icons, Eyecatcher oder Fotos in Java-Programme einbinden.<br>
'''Dieses Tutorial versucht sämtliche Möglichkeiten und Sachverhalte vom Laden von Grafikdateien in Java näher zu beleuchten und geht dabei auch die Unterschiede zwischen AWT und Swing ein.'''
+
Im Folgenden soll anhand von Code-Beispielen gezeigt werden, wie unter verschiedenen Bedingungen und [[GUI]]-Schnittstellen ([https://wiki.byte-welt.net/wiki/Kategorie:AWT AWT] / [https://wiki.byte-welt.net/wiki/Kategorie:Swing Swing]) Grafiken eingebunden werden können.<br>
 +
'''Dieses Tutorial versucht sämtliche Möglichkeiten und Sachverhalte vom Laden von Grafikdateien in Java näher zu beleuchten und geht dabei auch auf die Unterschiede zwischen AWT, Swing und JavaFX ein.'''</div>
 +
 
 +
'''Autor: Gernot Segieth'''
 +
 
 
=Kleiner Pfad-Exkurs=
 
=Kleiner Pfad-Exkurs=
 
Das häufigste Problem, das von Einsteigern beschrieben wird, ist das Laden von Bildern aus verschiedensten Quellen und da besonders, die Einbindung über die URL oder den Pfad zum Bild.
 
Das häufigste Problem, das von Einsteigern beschrieben wird, ist das Laden von Bildern aus verschiedensten Quellen und da besonders, die Einbindung über die URL oder den Pfad zum Bild.
 
Denn oft möchte man ein Bild laden, welches sich nicht im gleichen Verzeichnis wie die Bytecode-Datei befindet.
 
Denn oft möchte man ein Bild laden, welches sich nicht im gleichen Verzeichnis wie die Bytecode-Datei befindet.
 
Die folgende kurze Einführung zeigt die Verwendung und die Schreibweisen der Angabe des Pfades zur Referenzierung von Grafikdateien.
 
Die folgende kurze Einführung zeigt die Verwendung und die Schreibweisen der Angabe des Pfades zur Referenzierung von Grafikdateien.
 +
 +
 +
==Was ist ein Pfad und wie ist er aufgebaut?==
 +
Dateien sind innerhalb eines Dateisystems in Verzeichnissen (Ordnern) gespeichert. Man kann Ordner mit Kisten vergleichen, in denen Dinge bestimmter Kategorien gesammelt werden. Bilder würde man sicher auch in einer separaten Kiste sammeln, statt sie mit Versicherungsdokumenten oder Büchern zu mischen.<br>
 +
Manchmal hat man in einer Bilderkiste auch weitere Kästchen, in denen Bilder zu einem ganz bestimmten Thema gesammelt sind.
 +
 +
Ein Pfad beschreibt nun den genauen Speicherplatz einer Datei in einem Dateisystem. Dabei werden sämtliche Kisten und Kästchen aneinander gereiht, bis man das einzelne Bild aus der Kiste oder dem Kästchen entnehmen kann.<br>
 +
Anders gesagt: beschreibt der Pfad den Weg, den man beschreiten muss, um zu einem bestimmten Ziel (hier ist es ein ganz bestimmtes Bild) zu gelangen.
 +
 +
Ein Beispiel:
 +
/Schrank/Bilderkiste/Urlaubsfotos/Strandkorb.jpg
 +
Diese Art des Pfades wird auch absoluter Pfad genannt, der Weg ist hier vom Start bis zum Ziel vollständig aufgeführt.
 +
 +
==Absolute Pfadangaben==
 +
Unter einem absoluten Pfad versteht man, ausgehend vom Wurzelverzeichnis, den genauen Speicherort einer Datei im Dateisystem.
 +
 +
===Beispiel Windows===
 +
Der absolute Pfad, um ein Bild auf der System-Festplatte unter Windows zu finden:
 +
<code>c:\users\byte-welt\pictures\bild.png</code>
 +
 +
Wenn man das aber so im Java-Code einer [[Klasse]] schreibt, wird der [[Compiler]] die Backslashes monieren. Der Backslash dient in Java zur Maskierung von Zeichen, die in Java selbst bereits eine Bedeutung haben.<br>
 +
Daher kann man den Pfad nun so schreiben:<br>
 +
<code>c:\\users\\byte-welt\\pictures\\bild.png</code>
 +
 +
Diese Schreibweise wird aber, insbesondere bei Verwendung von relativen Pfaden, nur unter Windows-Systemen ausführbar sein.
 +
 +
Daher kann der Pfad (abgesehen vom Laufwerksbuchstaben) in Java-Code am besten immer so geschreiben werden:<br>
 +
<code>c:/users/byte-welt/pictures/bild.png</code>
 +
 +
Der Compiler wird dann nichts mehr bemängeln und die JRE wird das Zeichen zur Pfadtrennung immer für das jeweilige Betriebssystem richtig setzen.
 +
 +
===Beispiel Linux===
 +
Der absolute Pfad, um ein Bild auf der Festplatte (/home-Partition) unter Linux zu finden:
 +
<code>/home/byte-welt/pictures/bild.png</code>
 +
 +
===Beispiel Internet===
 +
Der absolute Pfad, um ein Bild von einem Webspace aus dem Internet zu laden:
 +
<code><nowiki>http://byte-welt.net/pictures/bild.png</nowiki></code>
  
 
==Relative Pfadangaben==
 
==Relative Pfadangaben==
 +
Unter einem relativen Pfad versteht man einen bekannten Teil des (möglicherweise unbekannten) absoluten (gesamten, existierenden) Pfades zu Dateien im Dateisystem.<br>
 +
Es geht hier also um den Speicherort einer Datei, ausgehend von dem Punkt im Dateisystem, an dem man sich gerade befindet. Man muss also gar nicht genau wissen, wo sich die gewünschte Datei im Dateisystem befindet. Es genügt, zu wissen, wie man vom aktuellen "Standort" aus dort hin gelangt.
 +
 +
Der aktuelle Standort wird mit einem Punkt symbolisiert. Zwei aufeinander folgende Punkte symbolisieren ein Verzeichnis über dem aktuellen Verzeichnis. Im Pfad bedeutet das, man geht einen Schritt zurück.<br>
 +
Die jeweiligen Verzeichnisse werden mit einem Slash (unter Unix-Systemen) oder einem Backslash (unter Windows) getrennt.
  
 
===Bilder im Verzeichnis der einbettenden Klasse===
 
===Bilder im Verzeichnis der einbettenden Klasse===
Zeile 17: Zeile 64:
 
zwei Ebenen tiefer:
 
zwei Ebenen tiefer:
 
<code>inhalt/bilder/bild.png</code>
 
<code>inhalt/bilder/bild.png</code>
 +
 +
<div style="width:50%;padding:1em 1em;margin:2em;background-color:pink;border-style:solid;border-width:2px;border-color:red;">'''Vorsicht Fehler:''' Ein '''/''' vor einem relativen Pfad wie <code>inhalt/bilder/bild.png</code> würde ihn zu einem [[Grafikdateien laden und anzeigen (Java)#Absolute Pfadangaben|absoluten Pfad]] machen!</div>
  
 
===Bilder eine Verzeichnisebene höher===
 
===Bilder eine Verzeichnisebene höher===
Zeile 24: Zeile 73:
 
<code>../../bild.png</code>
 
<code>../../bild.png</code>
  
==Absolute Pfadangaben==
+
zwei Ebenen höher mit anschließendem Wechsel in ein anderes darunter liegendes Verzeichnis:
 +
<code>../../audio/soundcheck.mp3</code>
  
===Beispiel Windows===
+
=Laden von Grafikdateien im AWT=
Der absolute Pfad, um ein Bild von der System-Festplatte unter Windows zu laden:
+
Im [[AWT]], welches die Standard-Schnittstelle für die Entwicklung grafischer Benutzeroberflächen bis zur Veröffentlichung von Java 1.2 war, wird das Einlesen von Grafikdaten in [[Java-Applets]] und Applikationen unterschiedlich gehandhabt. Bis auf den gleichen Namen der benutzten [[Methode]] zum Einlesen, müssen hier verschiedene Konzepte angewendet werden. Das führt oft zu Verwirrung und Vorgehensweisen, die unnötig sind.
<code>c:\users\byte-welt\pictures\bild.png</code>
 
  
===Beispiel Linux===
 
Der absolute Pfad, um ein Bild von der System-Festplatte unter Linux zu laden:
 
<code>/home/byte-welt/pictures/bild.png</code>
 
 
===Beispiel Internet===
 
Ein Bild von einem Webspace laden:
 
<code>http://byte-welt.net/pictures/bild.png</code>
 
 
=Laden von Grafikdateien im AWT=
 
Im AWT, welches die Standard-Schnittstelle für die Entwicklung grafischer Benutzeroberflächen bis zur Veröffentlichung von Java 1.2 war, wird das Einlesen von Grafikdaten in [[Applet]]s und Applikationen unterschiedlich gehandhabt. Bis auf den gleichen Namen der benutzten [[Methode]] zum Einlesen, müssen hier verschiedene Konzepte angewendet werden. Das führt oft zu Verwirrung und Vorgehensweisen, die unnötig sind.
 
 
==Applets==
 
==Applets==
  
 
===Laden von Bildern in Applets===
 
===Laden von Bildern in Applets===
Da Applets auf einem [[Webserver]] gespeichert sind und nach dem Laden in den [[Browser]] externe Resourcen wie Bilder ebenfalls aus dem Internet nachladen, werden die URLs (Quellenanzeiger) der Resourcen meist ausgehend vom URL des Applets angegeben. Das heißt: getCodeBase() liefert den URL des Applets im Internet bzw. Netzwerk. Und davon ausgehend kann nun der exakte [[Pfad]] zu unserem Bild angegeben werden.
+
Da [[Java-Applets]] auf einem [[Webserver]] gespeichert sind und nach dem Laden in den [[Browser]] externe Ressourcen wie Bilder ebenfalls aus dem Internet nachladen, werden die URLs (Quellenanzeiger) der Ressourcen meist ausgehend vom {{JAPI|URL}} des Applets angegeben. Das heißt: <code>getCodeBase()</code> liefert den URL des Applets im Internet bzw. Netzwerk. Und davon ausgehend kann nun der exakte [[Pfad]] zu unserem Bild angegeben werden.
  
 
Beispiele:
 
Beispiele:
<code=java>
+
<syntaxhighlight lang="java">
 
Image image1 = getImage(getCodeBase(),"Bild1.jpg"); //Das Bild liegt hier im gleichen Verzeichnis, wie das Applet.
 
Image image1 = getImage(getCodeBase(),"Bild1.jpg"); //Das Bild liegt hier im gleichen Verzeichnis, wie das Applet.
  
Zeile 54: Zeile 93:
  
 
Image image4 = getImage(new URL("http://www.meine-domain.de/bilder/Bild3.jpg")); //Nicht erlaubt! Wirft eine AccessControlException.
 
Image image4 = getImage(new URL("http://www.meine-domain.de/bilder/Bild3.jpg")); //Nicht erlaubt! Wirft eine AccessControlException.
</code=java>
+
</syntaxhighlight>
Beim Programmieren sollte darauf geachtet werden, dass generell Slashes (also '''/''') als Pfadseparatoren verwendet werden. Auch unter Windows! Sonst müsste jeder Pfadseparator escaped werden, was wieder zu einer Plattformabhängigkeit führt.
+
Beim Programmieren sollte darauf geachtet werden, dass generell Slashes (also '''/''') als Pfadseparatoren verwendet werden. Auch unter Windows! Sonst müsste jeder Pfadseparator ''escaped'' werden, was wieder zu einer Plattformabhängigkeit führt.
  
 
===Einfache Applet-Klasse===
 
===Einfache Applet-Klasse===
Die einfachste Variante, eine Grafik in ein Applet (AWT) einzubinden ist, sie von der URL einzulesen und in der paint()-Methode direkt auf die Appletfläche zu zeichnen.
+
Die einfachste Variante, eine Grafik in ein [[Java-Applets]] ([[AWT]]) einzubinden ist, sie von der URL einzulesen und in der <code>paint()</code>-Methode direkt auf die Appletfläche zu zeichnen.
  
<code=java>import java.awt.*;
+
<syntaxhighlight lang="java">import java.awt.*;
 
import java.applet.*;
 
import java.applet.*;
  
Zeile 76: Zeile 115:
 
       }
 
       }
 
   }
 
   }
}</code=java>
+
}</syntaxhighlight>
  
Diese Variante ist aber wenig effizient und häufig kommt es vor, dass kein Bild ausgegeben wird, obwohl der URL und der Pfad zum Bild stimmen.
+
Diese Variante ist aber wenig effizient und häufig kommt es vor, dass kein Bild ausgegeben wird, obwohl der {{JAPI|URL}} und der Pfad zum Bild stimmen.
 
Das Einlesen des Bildes dauert hier bei größeren und/oder mehreren Dateien etwas länger, so dass die paint()-Methode schon ausgeführt wird, obwohl das Laden des Bildes noch nicht abgeschlossen ist.
 
Das Einlesen des Bildes dauert hier bei größeren und/oder mehreren Dateien etwas länger, so dass die paint()-Methode schon ausgeführt wird, obwohl das Laden des Bildes noch nicht abgeschlossen ist.
In der Java-Konsole würde in diesem Fall eine NullPointerException ausgegeben werden, wenn '''image''' nicht auf ''null'' geprüft werden würde.
+
In der Java-Konsole würde in diesem Fall eine {{JAPI|NullPointerException}} ausgegeben werden, wenn '''image''' nicht auf ''null'' geprüft werden würde.
 
Wegen der Prüfung, stürzt das Programm in dem Fall nicht ab, es zeichnet aber u. U. auch kein Bild.
 
Wegen der Prüfung, stürzt das Programm in dem Fall nicht ab, es zeichnet aber u. U. auch kein Bild.
 
Um sicherzustellen, dass das Bild fertig geladen ist, bevor die Zeichenroutine angestoßen wird, wird der Einsatz der Klasse [http://wiki.byte-welt.net/wiki/Grafikdateien_laden_und_anzeigen#Einsatz_des_MediaTrackers MediaTracker] empfohlen.
 
Um sicherzustellen, dass das Bild fertig geladen ist, bevor die Zeichenroutine angestoßen wird, wird der Einsatz der Klasse [http://wiki.byte-welt.net/wiki/Grafikdateien_laden_und_anzeigen#Einsatz_des_MediaTrackers MediaTracker] empfohlen.
  
 
==Einsatz des MediaTrackers==
 
==Einsatz des MediaTrackers==
Um sicher zu stellen, dass ein Bild erst dann auf eine AWT-Anwendung gezeichnet wird, wenn es wirklich vollständig geladen wurde, bedient man sich der Klasse [http://docs.oracle.com/javase/7/docs/api/java/awt/MediaTracker.html java.awt.MediaTracker], welche das Laden der Dateien in einem extra [[Thread]] überwacht und die Kontrolle ans Programm zurückgibt, wenn die Bilder geladen wurden.
+
Um sicher zu stellen, dass ein Bild erst dann auf eine AWT-Anwendung gezeichnet wird, wenn es wirklich vollständig geladen wurde, bedient man sich der Klasse {{JAPI|MediaTracker}}, welche das Laden der Dateien in einem extra [[Thread]] überwacht und die Kontrolle ans Programm zurückgibt, wenn die Bilder geladen wurden.
  
Beispiel:
+
<syntaxhighlight lang="java">import java.awt.*;
<code=java>import java.awt.*;
 
 
import java.applet.*;
 
import java.applet.*;
  
Zeile 116: Zeile 154:
 
       }
 
       }
 
   }
 
   }
}</code=java>
+
}</syntaxhighlight>
 
Auch hier, liegt das Bild im gleichen Verzeichnis, wie das Applet.<br>
 
Auch hier, liegt das Bild im gleichen Verzeichnis, wie das Applet.<br>
Die Vorgehensweise bei der Benutzung von MediaTracker in Applikationen ist die gleiche, nur dass Bilder dort mit der getImage()-Methode aus [http://docs.oracle.com/javase/7/docs/api/java/awt/Toolkit.html java.awt.Toolkit] geladen werden.
+
Die Vorgehensweise bei der Benutzung von MediaTracker in Applikationen ist die gleiche, nur dass Bilder dort mit der <code>getImage()</code>-Methode aus {{JAPI|Toolkit}} geladen werden.
  
 
==AWT-Applikationen==
 
==AWT-Applikationen==
Zeile 124: Zeile 162:
 
===Laden von Bildern für AWT-Applikationen===
 
===Laden von Bildern für AWT-Applikationen===
 
Anwendungen, welche das AWT als GUI-Schnittstelle anwenden, greifen auf die Klasse java.awt.Toolkit zurück, um Bilder zu laden
 
Anwendungen, welche das AWT als GUI-Schnittstelle anwenden, greifen auf die Klasse java.awt.Toolkit zurück, um Bilder zu laden
<code=java>
+
<syntaxhighlight lang="java">
 
Image image = Toolkit.getDefaultToolkit().getImage("picture.jpg");
 
Image image = Toolkit.getDefaultToolkit().getImage("picture.jpg");
</code=java>
+
</syntaxhighlight>
Genau wie bei Applets muss hier damit gerechnet werden, dass u. U. das Bilder nicht gezeichnet wird, obwohl der Pfad zum Bild stimmt. Stattdessen erhält man eine NullPointerException.
+
Genau wie bei [[Java-Applets]] muss hier damit gerechnet werden, dass u. U. das Bilder nicht gezeichnet wird, obwohl der Pfad zum Bild stimmt. Stattdessen erhält man eine [[NullPointerException]] (siehe [[Was ist eine Exception?]]).
 
Auch hier empfiehlt sich zusätzlich der Einsatz von [http://wiki.byte-welt.net/wiki/Grafikdateien_laden_und_anzeigen#Einsatz_des_MediaTrackers MediaTracker], um sicherzustellen, dass das Bild im Speicher ist, bevor die Zeichenroutine angestoßen wird.
 
Auch hier empfiehlt sich zusätzlich der Einsatz von [http://wiki.byte-welt.net/wiki/Grafikdateien_laden_und_anzeigen#Einsatz_des_MediaTrackers MediaTracker], um sicherzustellen, dass das Bild im Speicher ist, bevor die Zeichenroutine angestoßen wird.
  
 
===Ausgabe von Bildern in GUI-Komponenten===
 
===Ausgabe von Bildern in GUI-Komponenten===
Die meisten GUI-Komponenten des AWT haben von Hause aus keine Möglichkeiten mitbekommen, um Bilder und Grafiken anzuzeigen. Diese Fähigkeiten müssen ihnen nachträglich vom Programmierer verliehen werden.
+
Die meisten GUI-Komponenten des [[AWT]] haben von Hause aus keine Möglichkeiten mitbekommen, um Bilder und Grafiken anzuzeigen. Diese Fähigkeiten müssen ihnen nachträglich vom Programmierer verliehen werden.
Dazu ist es erforderlich, vom gewünschten Objekt-Typ zu erben und Methoden zur Ausgabe einzufügen. Im Folgenden werden wir das am Beispiel eines [http://docs.oracle.com/javase/7/docs/api/java/awt/Panel.html java.awt.Panel] demonstrieren.
+
Dazu ist es erforderlich, vom gewünschten Objekt-Typ zu erben und Methoden zur Ausgabe einzufügen. Im Folgenden werden wir das am Beispiel eines {{JAPI|Panel}} demonstrieren.
<code=java>
+
<syntaxhighlight lang="java">
 
public class ImagePanel extends Panel {
 
public class ImagePanel extends Panel {
 
   private Image image;
 
   private Image image;
Zeile 143: Zeile 181:
 
   public void setImage(Image image) {
 
   public void setImage(Image image) {
 
       this.image = image;
 
       this.image = image;
      setPreferredSize(new Dimension(image.getWidth(this), image.getHeight(this)));
 
 
       repaint();
 
       repaint();
 +
  }
 +
 +
  public Dimension getPreferredSize() {
 +
      if(image != null) {
 +
          return new Dimension(image.getWidth(this), image.getHeight(this)));
 +
      }
 +
      return super.getPreferredSize();
 
   }
 
   }
  
Zeile 154: Zeile 198:
 
   }
 
   }
 
}
 
}
</code=java>
+
</syntaxhighlight>
Dieses Panel kann in AWT-Anwendungen nun Bilder anzeigen. LayoutManager berechnen auch den Platz, den das Label im Layout benötigen wird.
+
Dieses Panel kann in AWT-Anwendungen nun Bilder anzeigen. [[LayoutManager]] berechnen auch den Platz, den das Label im Layout benötigen wird.
  
 
=Laden von Grafikdateien in Swing=
 
=Laden von Grafikdateien in Swing=
 
In Swing haben die Java-Erfinder von Sun sehr leistungsfähige Klassen für das Einlesen von Grafikdaten aus unterschiedlichen Quellen entwickelt, die auch die Anwendung in Applets und Applikationen vereinheitlicht.
 
In Swing haben die Java-Erfinder von Sun sehr leistungsfähige Klassen für das Einlesen von Grafikdaten aus unterschiedlichen Quellen entwickelt, die auch die Anwendung in Applets und Applikationen vereinheitlicht.
 +
 +
 
==Varianten zum Einbinden von Grafiken==
 
==Varianten zum Einbinden von Grafiken==
 
Viele Wege führen bekanntlich nach Rom, so auch beim erfolgreichen Laden und Anzeigen von Grafikdateien in Java.<br>
 
Viele Wege führen bekanntlich nach Rom, so auch beim erfolgreichen Laden und Anzeigen von Grafikdateien in Java.<br>
 +
 
===ImageIO===
 
===ImageIO===
'''javax.imageio.ImageIO''' ist eine sehr effiziente und einfach zu handhabende Klasse zum Laden von Grafikdateien.<br>
+
{{JAPI|javax.imageio.ImageIO}} ist eine sehr effiziente und einfach zu handhabende Klasse zum Laden von Grafikdateien.<br>
Sie stellt u.a. Methoden bereit, um Bilder aus verschiedenen Quellen zu laden. So z.B. aus einer Datei, einem InputStream oder von einer URL.
+
Sie stellt u.a. Methoden bereit, um Bilder aus verschiedenen Quellen zu laden. So z.B. aus einer Datei, einem {{JAPI|InputStream}} oder von einer {{JAPI|URL}}.
Ergebnis des Einlesens mit ImageIO ist immer ein Objekt vom Typ BufferedImage, welches die Klasse java.awt.Image erweitert.
+
Ergebnis des Einlesens mit {{JAPI|ImageIO}} ist immer ein Objekt vom Typ {{JAPI|BufferedImage}}, welches die Klasse {{JAPI|Image}} erweitert.
  
  
 
'''Laden aus einer Datei mit Angabe ihres Namens:'''<br>
 
'''Laden aus einer Datei mit Angabe ihres Namens:'''<br>
<code=java>Image image = ImageIO.read(new File("demo.jpg"));</code=java>
+
<syntaxhighlight lang="java">Image image = ImageIO.read(new File("demo.jpg"));</syntaxhighlight>
Diese Variante ist für das Laden von Bildern aus Dateien des lokalen Dateisystems geeignet. Z.B. mit Hilfe von [http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html JFileChooser]<br>
+
Diese Variante ist für das Laden von Bildern aus Dateien des lokalen Dateisystems geeignet. Z.B. mit Hilfe von [[JFileChooser - Dateien auswählen|JFileChooser]].
Sie kommt aber nicht für die Verwendung von Applets in Frage, weil mit File-Zugriffen auf dem Client unerlaubte Operationen versucht werden würden.
+
 
 +
Sie kommt aber nicht für die Verwendung von Applets in Frage, weil mit File-Zugriffen auf dem [[Client]] unerlaubte Operationen versucht werden würden.
 
Sie ist also nur für den Gebrauch in Applikationen denkbar.
 
Sie ist also nur für den Gebrauch in Applikationen denkbar.
  
  
 
'''Laden eines Bildes aus einem InputStream:'''<br>
 
'''Laden eines Bildes aus einem InputStream:'''<br>
<code=java>Image image = ImageIO.read(getClass().getResource("demo.jpg"));</code=java>  
+
<syntaxhighlight lang="java">Image image = ImageIO.read(getClass().getResource("demo.jpg"));</syntaxhighlight>
''getClass().getResource("...")'' erzeugt hier einen InputStream zur Datei. Diese Variante kommt bspw. zum Einsatz, wenn sich Bilder innerhalb einer Jar-Datei befinden. Sie funktioniert aber auch, wenn die Klassen und Grafikdateien noch unverpackt im lokalen Dateisystem liegen. Man braucht also nichts mehr verändern, wenn man später aus den fertigen Klassen eine Jar-Datei erzeugt.
+
<code>getClass().getResource("...")</code> <span style="color: green; font-weight: bold;"> erzeugt hier einen {{JAPI|InputStream}} zur Datei. Diese Variante kommt bspw. zum Einsatz, wenn sich Bilder innerhalb einer [[JAR-Datei|Jar-Datei]] befinden. Sie funktioniert aber auch, wenn die [[Klasse|Klassen]] und Grafikdateien noch unverpackt im lokalen Dateisystem liegen. Man braucht also nichts mehr verändern, wenn man später aus den fertigen Klassen eine Jar-Datei erzeugt.</span>
  
  
 
'''Laden eines Bildes in einem Package relativ zu dieser Klasse aus einem InputStream:'''<br>
 
'''Laden eines Bildes in einem Package relativ zu dieser Klasse aus einem InputStream:'''<br>
<code=java>Image image = ImageIO.read(getClass().getResource("../images/demo.jpg"));</code=java>  
+
<syntaxhighlight lang="java">Image image = ImageIO.read(getClass().getResource("../images/demo.jpg"));</syntaxhighlight>  
 
Es wird ein InputStream zur Datei in einer Jar-Datei erzeugt, der sie aus einem Verzeichnis relativ zu dieser Klasse läd.
 
Es wird ein InputStream zur Datei in einer Jar-Datei erzeugt, der sie aus einem Verzeichnis relativ zu dieser Klasse läd.
  
  
 
'''Laden eines Bildes in einem Package absolut zu einer Klasse aus einem InputStream:'''<br>
 
'''Laden eines Bildes in einem Package absolut zu einer Klasse aus einem InputStream:'''<br>
<code=java>Image image = ImageIO.read(getClass().getResource("/de/any-domain/project/images/demo.jpg"));</code=java>  
+
<syntaxhighlight lang="java">Image image = ImageIO.read(getClass().getResource("/de/any-domain/project/images/demo.jpg"));</syntaxhighlight>
 
Es wird ein InputStream zur Datei erzeugt, der ausgehend vom obersten Package ganz genau den Speicherort in einer Jar-Datei spezifiziert.
 
Es wird ein InputStream zur Datei erzeugt, der ausgehend vom obersten Package ganz genau den Speicherort in einer Jar-Datei spezifiziert.
 +
 +
 +
'''Laden eines Bildes im statischen Kontext:'''
 +
<syntaxhighlight lang="java">ImageIcon icon = new ImageIcon(MyClass.class.getResource("demo.jpg"));</syntaxhighlight>
 +
In einem statischen Kontext, das heißt, innerhalb einer statischen Methode, funktioniert das Ermitteln des Klassennamen mit der <code>getClass()</code>-Methode nicht. Hier muss der Name der Klasse als Ausgangspunkt des Pfades zum zu ladenden Bild fest verdrahtet werden. Anderenfalls wird der Compiler einen Fehler ähnlich diesem ausgeben:
 +
MyClass.java:123: error: non-static method getClass() cannot be referenced from a static context
  
  
 
'''Laden eines Bildes von einer URL:'''<br>
 
'''Laden eines Bildes von einer URL:'''<br>
<code=java>Image image = ImageIO.read(new URL("http://www.any-domain.de/images/demo.jpg"));</code=java>
+
<syntaxhighlight lang="java">Image image = ImageIO.read(new URL("http://www.any-domain.de/images/demo.jpg"));</syntaxhighlight>
 
Diese Variante kommt zum Einsatz, wenn Bilder aus einem Netzwerk geladen werden sollen.
 
Diese Variante kommt zum Einsatz, wenn Bilder aus einem Netzwerk geladen werden sollen.
  
Zeile 196: Zeile 250:
 
Weil dabei auch etwas schief gehen kann, muss der Abschnitt jeweils in einem try-catch - Block eingebaut werden.
 
Weil dabei auch etwas schief gehen kann, muss der Abschnitt jeweils in einem try-catch - Block eingebaut werden.
  
'''ImageIO wird meistens dann benutzt, wenn man Grafikdateien laden und diese später selbst auf GUI-Komponenten zeichnen möchte.'''
+
'''Merksatz: ImageIO wird meistens dann benutzt, wenn man Grafikdateien laden und diese später selbst auf GUI-Komponenten zeichnen möchte.'''
  
 
===ImageIcon===
 
===ImageIcon===
[[Objekt]]e von ImageIcon sind zur direkten Verwendung auf Swing-GUI-Komponenten wie bspw. JButtons, JLabels, JMenuItems etc. vorgesehen. Sie sind die Repräsentation von Icons oder Bildern, die auf der lokalen Festplatte, in einem Netzwerk, oder bereits im Speicher als Image-Objekt vorliegen.<br>
+
[[Objekt|Objekte]] von {{JAPI|ImageIcon}} sind zur direkten Verwendung auf Swing-GUI-Komponenten wie bspw. {{JAPI|JButton}}, {{JAPI|JLabel}}, {{JAPI|JMenuItem}} etc. vorgesehen. Sie sind die Repräsentation von Icons oder Bildern, die auf der lokalen Festplatte, in einem Netzwerk, oder bereits im Speicher als Image-Objekt vorliegen.<br>
 
'''javax.swing.ImageIcon''' ist also eine konkrete Implementierung des '''Icon'''-Interfaces, welches grundlegende Methoden für die Arbeit mit Icons oder Abbildungen definiert.<br>
 
'''javax.swing.ImageIcon''' ist also eine konkrete Implementierung des '''Icon'''-Interfaces, welches grundlegende Methoden für die Arbeit mit Icons oder Abbildungen definiert.<br>
Das Laden der Bilder wird im Hintergrund bereits mit dem '''java.awt.Mediatracker''' überwacht, so dass die Bilder auf jeden Fall im Speicher sind, bevor sie gezeichnet werden.<br>
+
Das Laden der Bilder wird im Hintergrund bereits mit dem {{JAPI|java.awt.Mediatracker}} überwacht, so dass die Bilder auf jeden Fall im Speicher sind, bevor sie gezeichnet werden.<br>
Der [[Konstruktor]] von ImageIcon erwartet die Übergabe des Pfades zum Speicherort bzw. den Namen der zu ladenen Datei in Form eines Strings oder in Form eines Images oder einer URL.
+
Der [[Konstruktor]] von ImageIcon erwartet die Übergabe des Pfades zum Speicherort bzw. den Namen der zu ladenen Datei in Form eines Strings oder in Form eines {{JAPI|Image}} oder einer {{JAPI|URL}}.
 
Demzufolge können Bilder aus Grafikdateien wie folgt in ImageIcon-Objekten referenziert werden:
 
Demzufolge können Bilder aus Grafikdateien wie folgt in ImageIcon-Objekten referenziert werden:
  
Referenzierung eines Bildes mit Hilfe eines vorher geladenen Image-Objektes:
+
'''Laden eines Bildes mit Hilfe eines vorher geladenen Image-Objektes:'''
<code=java>
+
<syntaxhighlight lang="java">
 
JButton button = null;
 
JButton button = null;
 
ImageIcon icon = null;
 
ImageIcon icon = null;
Zeile 218: Zeile 272:
 
}
 
}
  
button = new JButton("Demo", icon);</code=java>
+
button = new JButton("Demo", icon);
 +
</syntaxhighlight>
 +
Diese Variante macht zur Illustration von einbettenden Komponenten (JButton, JLabel) weniger Sinn. Eleganter ist der Weg über ImageIcon.
 +
 
 +
'''Mehr zum Thema [[JButton]]...'''
  
Das gleiche Ergebnis erhalten wir mit Referenzierung eines Bildes mit Hilfe des Dateinamens:
+
 
<code=java>
+
'''Laden eines Bildes mit Hilfe der Klasse ImageIcon:'''
 +
<syntaxhighlight lang="java">
 
ImageIcon icon = new ImageIcon("demo.jpg");
 
ImageIcon icon = new ImageIcon("demo.jpg");
JButton button = new JButton("Demo", icon);</code=java>
+
JButton button = new JButton("Demo", icon);
Das Bild befindet sich bei diesem Beipsiel in der lokalen Verzeichnisebene, im gleichen Verzeichnis ''dieser'' Klasse.
+
</syntaxhighlight>
 +
Das Bild befindet sich bei diesem Beispiel in der lokalen Verzeichnisebene, im gleichen Verzeichnis ''dieser'' Klasse.
 +
 
  
Referenzierung eines Bildes in einem Netzwerk mit Hilfe einer URL:
+
'''Laden eines Bildes in einem Netzwerk mit Hilfe einer URL:'''
<code=java>
+
<syntaxhighlight lang="java">
 
ImageIcon icon = new ImageIcon(new URL("http://www.any-domain.de/images/demo.jpg"));
 
ImageIcon icon = new ImageIcon(new URL("http://www.any-domain.de/images/demo.jpg"));
JButton button = new JButton("Demo", icon);</code=java>
+
JButton button = new JButton("Demo", icon);
 +
</syntaxhighlight>
 +
 
  
Referenzierung eines Bildes, welches in der gleichen Jar-Datei gespeichert wurde.
+
'''Laden eines Bildes, welches in der gleichen Jar-Datei gespeichert wurde:'''
<code=java>
+
<syntaxhighlight lang="java">
 
ImageIcon icon = new ImageIcon(getClass().getResource("demo.jpg"));
 
ImageIcon icon = new ImageIcon(getClass().getResource("demo.jpg"));
JButton button = new JButton("Demo", icon);</code=java>
+
JButton button = new JButton("Demo", icon);
 +
</syntaxhighlight>
 +
 
 +
 
 +
'''Laden eines Bildes im statischen Kontext:'''
 +
<syntaxhighlight lang="java">
 +
ImageIcon icon = new ImageIcon(MyClass.class.getResource("demo.jpg"));
 +
JButton button = new JButton("Demo", icon);
 +
</syntaxhighlight>
 +
In einem statischen Kontext, das heißt, innerhalb einer statischen Methode, funktioniert das Ermitteln des Klassennamen mit der <code>getClass()</code>-Methode nicht. Hier muss der Name der Klasse als Ausgangspunkt des Pfades zum zu ladenden Bild fest verdrahtet werden. Anderenfalls wird der Compiler einen Fehler ähnlich diesem ausgeben:
 +
MyClass.java:123: error: non-static method getClass() cannot be referenced from a static context
 +
 
 +
'''Merksatz: Ein ImageIcon wird immer nach den Vorgaben der einbettenden Komponente (JLabel, JButton etc.) gezeichnet bzw. angeordnet. Man hat hier also weniger Einfluss auf die Darstellung.'''
 +
 
 +
==Bilder als Hintergrund==
 +
In unserem Artikel [[Hintergrundbild in eine GUI einfügen (Java)|Hintergrundbild in eine GUI einfügen]] erklären wir an einem Beispiel, wie man in Swing Hintergrundbilder in eine GUI oder GUI-Komponenten bekommt.
 +
 
 +
Manchmal braucht man auch die [[Mit Java die Farbe eines Pixels aus einem Bild entnehmen|Farbe eines Pixels aus einem Bild]], um eine Farbe für eine Hintergrundkomponente, bspw einen Rahmen zu bestimmen.
 +
 
 +
=Laden von Bildern in JavaFX=
 +
Swing verliert nach und nach den Einfluss in der GUI-Programmierung in Java. JavaFX bietet gegenüber Swing weitaus mehr Möglichkeiten bei der Gestaltung von Benutzeroberflächen.<br>
 +
Auch der Code zum Einbinden von Bildern ändert sich. Das wollen wir im Folgenden anhand von Beispielen demonstrieren. (Vielen Dank an unseren Benutzer '''ionutbaiu''' für das Kapitel)
 +
 
 +
Die Änderungen zum Laden von Bildern in JavaFX gegenüber Swing bestehen in den Folgenden Punkten:
 +
 
 +
1. Es wird nun die Klasse {{JAPI|javafx.scene.image.Image}} im Gegensatz zu {{JAPI|java.awt.Image}} verwendet.<br>
 +
2. Die Image-Klasse besitzt nun verschiedene Konstruktoren, die im wesentlichen die Aufgaben der Read-Funktionen aus {{JAPI|ImageIO}} ersetzen, um Bilder aus verschiedenen Quellen zu laden.
 +
 
 +
In JavaFX gibt es mehrere Möglichkeiten Bilder zu verwenden.
 +
 
 +
==Bilder direkt verwenden==
 +
Um Bilder direkt zu verwenden gibt es zudem die Klasse {{JAPI|ImageView}}, diese ist weitestgehend das Pendant zur Klasse {{JAPI|ImageIcon}}.
 +
 
 +
'''1. Bild laden'''
 +
<syntaxhighlight lang="java>Image imgIcon = new Image(getClass().getResource("icons/icon.png").toExternalForm());</syntaxhighlight>
 +
 
 +
'''2. ImageView mit Bild erstellen'''
 +
<syntaxhighlight lang="java>ImageView imgView = new ImageView(imgIcon);</syntaxhighlight>
 +
 
 +
oder direkt
 +
<syntaxhighlight lang="java>ImageView imgView = new ImageView(getClass().getResource("icons/icon.png").toExternalForm());</syntaxhighlight>
 +
 
 +
'''3. ImageView dem Scene-Graph hinzufügen'''
 +
<syntaxhighlight lang="java>root.getChildren().add(imgView);</syntaxhighlight>
 +
 
 +
oder z.B. einem Button das Bild in Form eines Icons hinzufügen.
 +
<syntaxhighlight lang="java>Button button = new Button("Button mit Bild", imgView);</syntaxhighlight>
 +
 
 +
==Bilder als Hintergrund==
 +
Bilder können als Hintergrund eines Elements verwendet werden.
 +
 
 +
Das vorgehen hierbei ist wie folgt.
 +
 
 +
'''1. Bild laden'''
 +
<syntaxhighlight lang="java">Image imgBackground = new Image(getClass().getResource("images/background.jpg").toExternalForm());</syntaxhighlight>
 +
 
 +
'''2. Bild in ein Hintergrundbild umwandeln'''
 +
<syntaxhighlight lang="java">
 +
    BackgroundImage backgroundImage = new BackgroundImage(
 +
                        imgBackground,
 +
                        BackgroundRepeat.NO_REPEAT,
 +
                        BackgroundRepeat.NO_REPEAT,
 +
                        BackgroundPosition.DEFAULT,
 +
                        BackgroundSize.DEFAULT);
 +
</syntaxhighlight>
 +
 
 +
'''3. Hintergrund erstellen'''
 +
<syntaxhighlight lang="java">Background background = new Background(backgroundImage);</syntaxhighlight>
 +
 
 +
'''4. Bei der Komponente (hier root) den neuen Hintergrund setzen'''
 +
<syntaxhighlight lang="java">root.setBackground(background);</syntaxhighlight>
 +
 
 +
==FXML und CSS==
 +
Mit JavaFX gibt es zudem die Möglichkeit [[FXML]] und [[CSS]] einzusetzen.
 +
Hierbei kann die Oberfläche in [[XML]] definiert werden und das Aussehen mit CSS beeinflusst werden, so daß eine saubere Trennung der Zuständigkeiten möglich ist.
 +
 
 +
Eine Oberfläche mit einem Button kann mit FXML wie folgt in der Datei ''picture.fxml'' definiert werden
 +
<syntaxhighlight lang="xml">
 +
    <?xml version="1.0" encoding="UTF-8"?>
 +
   
 +
    <?import java.lang.*?>
 +
    <?import java.util.*?>
 +
    <?import javafx.scene.*?>
 +
    <?import javafx.scene.control.*?>
 +
    <?import javafx.scene.layout.*?>
 +
   
 +
    <AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="picture.PictureController">
 +
        <children>
 +
            <Button fx:id="button" layoutX="10" layoutY="10" onAction="#handleButtonAction" text="Button with Icon" />       
 +
        </children>
 +
    </AnchorPane>
 +
</syntaxhighlight>
 +
 
 +
In dieser Datei ist noch nichts bezüglich der Bilder zu finden. Um nun Bilder den einzelnen Elementen zuzuweisen wird eine datei pictures.css die so aussieht verwendet.
 +
<syntaxhighlight lang="css>
 +
    #AnchorPane {
 +
        -fx-background-image: url(images/background.jpg);
 +
        -fx-background-repeat: no-repeat;
 +
        -fx-background-position: center center;
 +
    }
 +
   
 +
    #button {
 +
        -fx-graphic: url(icons/icon.png);
 +
    }
 +
</syntaxhighlight>
 +
 
 +
 
 +
Um die Verknüpfung zwischen FXML und CSS zu bekommen, haben die Elemente in der FXML Datei jeweils eine ID.
 +
(<code>id="AnchorPane"</code>, sowie <code>fx:id="button"</code>)
 +
 
 +
In der CSS Datei werden diese Elemente mit dem Selektor <code>#AnchorPane</code> und <code>#button</code> herausgesucht um dort das Aussehen und die Bilder zu setzen.
 +
 
 +
Um FXML- und CSS-Datei in einer Anwendung zu verbinden kann man wie folgt vorgehen:
 +
 
 +
'''1. View aus der FXML-Datei laden'''
 +
<syntaxhighlight lang="java>Parent root = FXMLLoader.load(getClass().getResource("picture.fxml"));</syntaxhighlight>
 +
 
 +
'''2. Scene erstellen und View via Konstruktor zuweisen.'''
 +
<syntaxhighlight lang="java>Scene scene = new Scene(root);</syntaxhighlight>
 +
 
 +
'''3. CSS-Stylesheet laden und der Scene hinzufügen.'''
 +
<syntaxhighlight lang="java>scene.getStylesheets().add(getClass().getResource("picture.css").toExternalForm());</syntaxhighlight>
  
 +
'''4. Anzeigen der Scene'''
 +
<syntaxhighlight lang="java>
 +
      stage.setScene(scene);
 +
      stage.show();
 +
</syntaxhighlight>
  
Ein ImageIcon wird immer nach den Vorgaben der einbettenden Komponente (JLabel, JButton etc.) gezeichnet bzw. angeordnet. Man hat hier also weniger Einfluss auf die Darstellung.
+
=Code-Beispiele=
  
 
==JApplets==
 
==JApplets==
 
In Swing-Applets kann für das effiziente Einlesen von Grafikdaten die Klasse javax.imageio.ImageIO verwendet werden.<br>
 
In Swing-Applets kann für das effiziente Einlesen von Grafikdaten die Klasse javax.imageio.ImageIO verwendet werden.<br>
 
Wie einfach ihre Benutzung ist, werden wir im Anschluss demonstrieren.
 
Wie einfach ihre Benutzung ist, werden wir im Anschluss demonstrieren.
 +
 
===Einfache JApplet-Klassen===
 
===Einfache JApplet-Klassen===
 
Zeichnen auf einen Container (JPanel), welcher dem JApplet als Hintergrund hinzugefügt wird:
 
Zeichnen auf einen Container (JPanel), welcher dem JApplet als Hintergrund hinzugefügt wird:
<code=java>
+
<syntaxhighlight lang="java">
 
import javax.swing.*;
 
import javax.swing.*;
 
import javax.imageio.*;
 
import javax.imageio.*;
Zeile 280: Zeile 470:
 
       }
 
       }
 
   }
 
   }
}</code=java>
+
}
 +
</syntaxhighlight>
  
 
Link: [[Einbinden von Applets in HTML-Dateien]]
 
Link: [[Einbinden von Applets in HTML-Dateien]]
  
 
===Applets in Jar-Dateien===
 
===Applets in Jar-Dateien===
Wenn sich das Applet gemeinsam mit der zu ladenden Grafik in einer Jar-Datei zusammengefasst wurden, muss die Grafik über den ClassLoader ins Applet geladen werden.
+
Wenn sich das [[Java-Applets]] gemeinsam mit der zu ladenden Grafik in einer [[JAR-Datei]] zusammengefasst wurden, muss die Grafik über den ClassLoader ins Applet geladen werden.
  
 
Zeichnen auf einen Container (JPanel), welcher dem JApplet als Hintergrund hinzugefügt wird:
 
Zeichnen auf einen Container (JPanel), welcher dem JApplet als Hintergrund hinzugefügt wird:
<code=java>
+
<syntaxhighlight lang="java">
 
import javax.swing.*;
 
import javax.swing.*;
 
import javax.imageio.*;
 
import javax.imageio.*;
Zeile 324: Zeile 515:
 
       }
 
       }
 
   }
 
   }
}</code=java>
+
}
 +
</syntaxhighlight>
  
 
Das Applet-Tag in der HTML-Datei muss jetzt angepasst werden, damit der Browser weiß, wo sich das Applet befindet.<br>
 
Das Applet-Tag in der HTML-Datei muss jetzt angepasst werden, damit der Browser weiß, wo sich das Applet befindet.<br>
Link: [http://wiki.byte-welt.net/wiki/Einbinden_von_Applets_in_HTML-Dateien Applet-Tag für Jar-Dateien]
+
Link: [[Einbinden von Applets in HTML-Dateien]] für Jar-Dateien
  
 
==Swing-Applikationen==
 
==Swing-Applikationen==
 
Auch Swing-Applikationen werden im Allgemeinen in Jar-Archiven zusammengefasst. Diese lassen sich auf jedem System per Doppelklick starten, oder per Webstart über das Internet laden.<br>
 
Auch Swing-Applikationen werden im Allgemeinen in Jar-Archiven zusammengefasst. Diese lassen sich auf jedem System per Doppelklick starten, oder per Webstart über das Internet laden.<br>
 
Hier also nun die Variante für eine Applikation. Auffällig ist, dass sich der Code des Panels gegenüber dem Applet nur leicht, der Code zum Laden der Bilder aber gar nicht verändert hat.
 
Hier also nun die Variante für eine Applikation. Auffällig ist, dass sich der Code des Panels gegenüber dem Applet nur leicht, der Code zum Laden der Bilder aber gar nicht verändert hat.
<code=java>
+
<syntaxhighlight lang="java">
 
import javax.swing.*;
 
import javax.swing.*;
 
import javax.imageio.*;
 
import javax.imageio.*;
Zeile 368: Zeile 560:
 
   }
 
   }
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
Das Ganze kann nun in einem Fenster angezeigt werden:
 
Das Ganze kann nun in einem Fenster angezeigt werden:
<code=java>
+
<syntaxhighlight lang="java">
 
import javax.swing.*;
 
import javax.swing.*;
  
Zeile 388: Zeile 580:
 
   }
 
   }
 
}
 
}
</code=java>
+
</syntaxhighlight>
 +
 
 +
==JavaFX-Applikationen ==
 +
Wenn man sich nun den Code einer entsprechenden JavaFX-Anwendung ansieht, könnte man meinen, dass es scheinbar Parallelen zu AWT und Swing gibt. Java-FX-Klassen haben nun kein vorangestelltes "J" mehr und die Initialisierung eines {{JAPI|javafx.scene.control.Button}} sieht aus, wie bei einem Swing-{{JAPI|JButton}}. Allerdings gibt es auch Neues, wie nun gezeigt wird:
 +
<syntaxhighlight lang="java">
 +
import java.io.PrintWriter;
 +
import java.io.StringWriter;
 +
import javafx.application.Application;
 +
import javafx.scene.Scene;
 +
import javafx.scene.control.Alert;
 +
import javafx.scene.control.Button;
 +
import javafx.scene.image.Image;
 +
import javafx.scene.image.ImageView;
 +
import javafx.scene.layout.Background;
 +
import javafx.scene.layout.BackgroundImage;
 +
import javafx.scene.layout.BackgroundPosition;
 +
import javafx.scene.layout.BackgroundRepeat;
 +
import javafx.scene.layout.BackgroundSize;
 +
import javafx.scene.layout.StackPane;
 +
import javafx.stage.Stage;
 +
 
 +
public class Picture extends Application {
 +
 
 +
    @Override
 +
    public void start(Stage primaryStage) {
 +
 
 +
        try {
 +
            Image imgBackground = new Image(getClass().getResource("images/background.jpg").toExternalForm());
 +
            BackgroundImage backgroundImage = new BackgroundImage(
 +
                    imgBackground,
 +
                    BackgroundRepeat.NO_REPEAT,
 +
                    BackgroundRepeat.NO_REPEAT,
 +
                    BackgroundPosition.DEFAULT,
 +
                    BackgroundSize.DEFAULT);
 +
            Background background = new Background(backgroundImage);
 +
 
 +
            Image imgIcon = new Image(getClass().getResource("icons/icon.png").toExternalForm());
 +
            ImageView imgView = new ImageView(imgIcon);
 +
 
 +
            Button btn = new Button("Button mit Icon", imgView);
 +
            btn.setText("Button mit Icon");
 +
 
 +
            StackPane root = new StackPane();
 +
            root.getChildren().add(btn);
 +
            root.setBackground(background);
 +
 
 +
            Scene scene = new Scene(root, 300, 250);
 +
 
 +
            primaryStage.setTitle("Bildbetrachter FX");
 +
            primaryStage.setScene(scene);
 +
            primaryStage.show();
 +
 
 +
        } catch (Exception e) {
 +
            Alert alert = new Alert(Alert.AlertType.ERROR);
 +
            alert.setTitle("Fehler");
 +
 
 +
            StringWriter sw = new StringWriter();
 +
            PrintWriter pw = new PrintWriter(sw);
 +
            e.printStackTrace(pw);
 +
 
 +
            alert.setContentText(sw.toString());
 +
 
 +
            alert.showAndWait();
 +
        }
 +
    }
 +
 
 +
    public static void main(String[] args) {
 +
        launch(args);
 +
    }
 +
 
 +
}
 +
</syntaxhighlight>
  
 
=Grafiken aus externen Jar-Dateien laden=
 
=Grafiken aus externen Jar-Dateien laden=
 
Im Internet sind reichlich freie Quellen zu finden, die spezielle Grafiken (Icons) für die visuelle Kennzeichnung und Verschönerung von GUI-Elementen eingesetzt werden können.<br>
 
Im Internet sind reichlich freie Quellen zu finden, die spezielle Grafiken (Icons) für die visuelle Kennzeichnung und Verschönerung von GUI-Elementen eingesetzt werden können.<br>
Diese Quellen liegen meist in gepackter Form als Zip-Archiv vor. Um sie für ein Java-Programm nutzbar zu machen, kann man eine solche Zip-Datei einfach in eine Jar-Datei umbenennen (Datei-Präfix ändern) oder auch, unter Beachtung der Lizenz, einzelne Dateien extrahieren und in eine neue Jar-Datei packen.
+
Diese Quellen liegen meist in gepackter Form als Zip-Archiv vor. Um sie für ein Java-Programm nutzbar zu machen, kann man eine solche Zip-Datei einfach in eine Jar-Datei umbenennen (Datei-Suffix ändern) oder auch, unter Beachtung der Lizenz, einzelne Dateien extrahieren und in eine neue Jar-Datei packen.
 
Den Weg, Grafikdateien aus der Jar-Datei zu laden, die auch unser Programm enthält, haben wir bereits oben gesehen.
 
Den Weg, Grafikdateien aus der Jar-Datei zu laden, die auch unser Programm enthält, haben wir bereits oben gesehen.
 
Wir werden uns nun aber mal ansehen, wie Grafikdateien aus externen Bibliotheken bzw. Archiven geladen werden können.
 
Wir werden uns nun aber mal ansehen, wie Grafikdateien aus externen Bibliotheken bzw. Archiven geladen werden können.
 +
  
 
==Bibliotheken im Classpath==
 
==Bibliotheken im Classpath==
 +
(Artikel noch einzufügen)
 +
  
 
==Bibliotheken außerhalb des Classpaths==
 
==Bibliotheken außerhalb des Classpaths==
Um Grafikdateien aus einer externen Jar-Datei zu laden, die sich nicht im Sichtbarkeitsbereich des ClassLoaders befindet, kann man den absoluten Pfad zur Jar-Datei entsprechend zusammenbauen:
+
Um Grafikdateien aus einer externen Jar-Datei zu laden, die sich nicht im Sichtbarkeitsbereich des ClassLoaders befindet, kann man den absoluten Pfad zur Jar-Datei entsprechend nach folgendem Schema zusammenbauen:
<code=java>URL jarPath = new URL("jar:file:Path/To/JarFile/jarfile.jar!"+innerPath);</code=java>
+
 
''innerPath'' bezeichnet hierbei den Pfad innerhalb der externen Jar-Datei zur Grafikdatei.
+
jar:protocol//:path/to/jarfile/jarfile.jar!/my/package
 +
 
 +
'''protocol''' bezeichnet hier z.B. ''http'' oder ''file''.
 +
Direkt nach der Jar-Datei folgt ein Ausrufezeichen. Was danach folgt ist der Pfad innerhalb der Jar-Datei, also die einzelnen Packages.
 +
 
 +
<syntaxhighlight lang="java">URL jarPath = new URL("jar:file://pfad/zur/jardatei/MeinProgramm.jar!/bilder/bild.jpg");</syntaxhighlight>
 +
''/bilder/bild.jpg'' bezeichnet hierbei den Pfad innerhalb der externen Jar-Datei zur Grafikdatei.
  
=Fragen stellen=
+
{{Fragen stellen}}
Wir haben hier bereits viele Dinge beim Umgang mit Grafiken in Java-Programmen besprochen.
+
[[Kategorie:AWT]]
Du hast immer noch Fragen? Dann hier im Byte-Welt-Forum: [http://forum.byte-welt.net/newthread.php?do=newthread&f=99 AWT, Swing, JavaFX & SWT]
+
[[Kategorie:Swing]]
[[Kategorie:Java]]
+
[[Kategorie:JavaFX]]
 +
[[Kategorie:Java 2D]]
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Tutorials (Java)]]

Aktuelle Version vom 14. November 2021, 16:44 Uhr

Häufig möchte man aus verschiedenen Gründen Grafikdateien, wie Bilder und Icons, Eyecatcher oder Fotos in Java-Programme einbinden.

Im Folgenden soll anhand von Code-Beispielen gezeigt werden, wie unter verschiedenen Bedingungen und GUI-Schnittstellen (AWT / Swing) Grafiken eingebunden werden können.

Dieses Tutorial versucht sämtliche Möglichkeiten und Sachverhalte vom Laden von Grafikdateien in Java näher zu beleuchten und geht dabei auch auf die Unterschiede zwischen AWT, Swing und JavaFX ein.

Autor: Gernot Segieth

Kleiner Pfad-Exkurs

Das häufigste Problem, das von Einsteigern beschrieben wird, ist das Laden von Bildern aus verschiedensten Quellen und da besonders, die Einbindung über die URL oder den Pfad zum Bild. Denn oft möchte man ein Bild laden, welches sich nicht im gleichen Verzeichnis wie die Bytecode-Datei befindet. Die folgende kurze Einführung zeigt die Verwendung und die Schreibweisen der Angabe des Pfades zur Referenzierung von Grafikdateien.


Was ist ein Pfad und wie ist er aufgebaut?

Dateien sind innerhalb eines Dateisystems in Verzeichnissen (Ordnern) gespeichert. Man kann Ordner mit Kisten vergleichen, in denen Dinge bestimmter Kategorien gesammelt werden. Bilder würde man sicher auch in einer separaten Kiste sammeln, statt sie mit Versicherungsdokumenten oder Büchern zu mischen.
Manchmal hat man in einer Bilderkiste auch weitere Kästchen, in denen Bilder zu einem ganz bestimmten Thema gesammelt sind.

Ein Pfad beschreibt nun den genauen Speicherplatz einer Datei in einem Dateisystem. Dabei werden sämtliche Kisten und Kästchen aneinander gereiht, bis man das einzelne Bild aus der Kiste oder dem Kästchen entnehmen kann.
Anders gesagt: beschreibt der Pfad den Weg, den man beschreiten muss, um zu einem bestimmten Ziel (hier ist es ein ganz bestimmtes Bild) zu gelangen.

Ein Beispiel:

/Schrank/Bilderkiste/Urlaubsfotos/Strandkorb.jpg

Diese Art des Pfades wird auch absoluter Pfad genannt, der Weg ist hier vom Start bis zum Ziel vollständig aufgeführt.

Absolute Pfadangaben

Unter einem absoluten Pfad versteht man, ausgehend vom Wurzelverzeichnis, den genauen Speicherort einer Datei im Dateisystem.

Beispiel Windows

Der absolute Pfad, um ein Bild auf der System-Festplatte unter Windows zu finden: c:\users\byte-welt\pictures\bild.png

Wenn man das aber so im Java-Code einer Klasse schreibt, wird der Compiler die Backslashes monieren. Der Backslash dient in Java zur Maskierung von Zeichen, die in Java selbst bereits eine Bedeutung haben.
Daher kann man den Pfad nun so schreiben:
c:\\users\\byte-welt\\pictures\\bild.png

Diese Schreibweise wird aber, insbesondere bei Verwendung von relativen Pfaden, nur unter Windows-Systemen ausführbar sein.

Daher kann der Pfad (abgesehen vom Laufwerksbuchstaben) in Java-Code am besten immer so geschreiben werden:
c:/users/byte-welt/pictures/bild.png

Der Compiler wird dann nichts mehr bemängeln und die JRE wird das Zeichen zur Pfadtrennung immer für das jeweilige Betriebssystem richtig setzen.

Beispiel Linux

Der absolute Pfad, um ein Bild auf der Festplatte (/home-Partition) unter Linux zu finden: /home/byte-welt/pictures/bild.png

Beispiel Internet

Der absolute Pfad, um ein Bild von einem Webspace aus dem Internet zu laden: http://byte-welt.net/pictures/bild.png

Relative Pfadangaben

Unter einem relativen Pfad versteht man einen bekannten Teil des (möglicherweise unbekannten) absoluten (gesamten, existierenden) Pfades zu Dateien im Dateisystem.
Es geht hier also um den Speicherort einer Datei, ausgehend von dem Punkt im Dateisystem, an dem man sich gerade befindet. Man muss also gar nicht genau wissen, wo sich die gewünschte Datei im Dateisystem befindet. Es genügt, zu wissen, wie man vom aktuellen "Standort" aus dort hin gelangt.

Der aktuelle Standort wird mit einem Punkt symbolisiert. Zwei aufeinander folgende Punkte symbolisieren ein Verzeichnis über dem aktuellen Verzeichnis. Im Pfad bedeutet das, man geht einen Schritt zurück.
Die jeweiligen Verzeichnisse werden mit einem Slash (unter Unix-Systemen) oder einem Backslash (unter Windows) getrennt.

Bilder im Verzeichnis der einbettenden Klasse

bild.png oder ./bild.png

Bilder eine Verzeichnisebene tiefer

inhalt/bild.png

zwei Ebenen tiefer: inhalt/bilder/bild.png

Vorsicht Fehler: Ein / vor einem relativen Pfad wie inhalt/bilder/bild.png würde ihn zu einem absoluten Pfad machen!

Bilder eine Verzeichnisebene höher

../bild.png

zwei Ebenen höher: ../../bild.png

zwei Ebenen höher mit anschließendem Wechsel in ein anderes darunter liegendes Verzeichnis: ../../audio/soundcheck.mp3

Laden von Grafikdateien im AWT

Im AWT, welches die Standard-Schnittstelle für die Entwicklung grafischer Benutzeroberflächen bis zur Veröffentlichung von Java 1.2 war, wird das Einlesen von Grafikdaten in Java-Applets und Applikationen unterschiedlich gehandhabt. Bis auf den gleichen Namen der benutzten Methode zum Einlesen, müssen hier verschiedene Konzepte angewendet werden. Das führt oft zu Verwirrung und Vorgehensweisen, die unnötig sind.

Applets

Laden von Bildern in Applets

Da Java-Applets auf einem Webserver gespeichert sind und nach dem Laden in den Browser externe Ressourcen wie Bilder ebenfalls aus dem Internet nachladen, werden die URLs (Quellenanzeiger) der Ressourcen meist ausgehend vom URL des Applets angegeben. Das heißt: getCodeBase() liefert den URL des Applets im Internet bzw. Netzwerk. Und davon ausgehend kann nun der exakte Pfad zu unserem Bild angegeben werden.

Beispiele:

Image image1 = getImage(getCodeBase(),"Bild1.jpg"); //Das Bild liegt hier im gleichen Verzeichnis, wie das Applet.

Image image2 = getImage(getCodeBase(),"../Bild2.jpg"); //Das Bild liegt hier im Verzeichnis über dem Applet.

Image image3 = getImage(getCodeBase(),"bilder/Bild3.jpg"); //Das Bild liegt hier vom Applet ausgehend in einem Unterverzeichnis bilder.

Image image4 = getImage(new URL("http://www.meine-domain.de/bilder/Bild3.jpg")); //Nicht erlaubt! Wirft eine AccessControlException.

Beim Programmieren sollte darauf geachtet werden, dass generell Slashes (also /) als Pfadseparatoren verwendet werden. Auch unter Windows! Sonst müsste jeder Pfadseparator escaped werden, was wieder zu einer Plattformabhängigkeit führt.

Einfache Applet-Klasse

Die einfachste Variante, eine Grafik in ein Java-Applets (AWT) einzubinden ist, sie von der URL einzulesen und in der paint()-Methode direkt auf die Appletfläche zu zeichnen.

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

public class PictureApplet extends Applet {
   private Image image;

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

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

Diese Variante ist aber wenig effizient und häufig kommt es vor, dass kein Bild ausgegeben wird, obwohl der URL und der Pfad zum Bild stimmen. Das Einlesen des Bildes dauert hier bei größeren und/oder mehreren Dateien etwas länger, so dass die paint()-Methode schon ausgeführt wird, obwohl das Laden des Bildes noch nicht abgeschlossen ist. In der Java-Konsole würde in diesem Fall eine NullPointerException ausgegeben werden, wenn image nicht auf null geprüft werden würde. Wegen der Prüfung, stürzt das Programm in dem Fall nicht ab, es zeichnet aber u. U. auch kein Bild. Um sicherzustellen, dass das Bild fertig geladen ist, bevor die Zeichenroutine angestoßen wird, wird der Einsatz der Klasse MediaTracker empfohlen.

Einsatz des MediaTrackers

Um sicher zu stellen, dass ein Bild erst dann auf eine AWT-Anwendung gezeichnet wird, wenn es wirklich vollständig geladen wurde, bedient man sich der Klasse MediaTracker, welche das Laden der Dateien in einem extra Thread überwacht und die Kontrolle ans Programm zurückgibt, wenn die Bilder geladen wurden.

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

public class PictureApplet extends Applet {
   private Image image;
   private MediaTracker tracker;

   public void init() {
      tracker = new MediaTracker(this);

      image = getImage(getCodeBase(),"Bild.jpg"); //Laden des Bildes anstoßen

      tracker.addImage(image, 0); //Image an den MediaTracker zur Überwachung übergeben

      try {
         tracker.waitForAll(); //auf alle zu ladenden Dateien warten
      }
      catch (InterruptedException e) {
         e.printStackTrace(); //Fehlerausgabe auf der Java-Konsole
      }
   }

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

Auch hier, liegt das Bild im gleichen Verzeichnis, wie das Applet.
Die Vorgehensweise bei der Benutzung von MediaTracker in Applikationen ist die gleiche, nur dass Bilder dort mit der getImage()-Methode aus Toolkit geladen werden.

AWT-Applikationen

Laden von Bildern für AWT-Applikationen

Anwendungen, welche das AWT als GUI-Schnittstelle anwenden, greifen auf die Klasse java.awt.Toolkit zurück, um Bilder zu laden

Image image = Toolkit.getDefaultToolkit().getImage("picture.jpg");

Genau wie bei Java-Applets muss hier damit gerechnet werden, dass u. U. das Bilder nicht gezeichnet wird, obwohl der Pfad zum Bild stimmt. Stattdessen erhält man eine NullPointerException (siehe Was ist eine Exception?). Auch hier empfiehlt sich zusätzlich der Einsatz von MediaTracker, um sicherzustellen, dass das Bild im Speicher ist, bevor die Zeichenroutine angestoßen wird.

Ausgabe von Bildern in GUI-Komponenten

Die meisten GUI-Komponenten des AWT haben von Hause aus keine Möglichkeiten mitbekommen, um Bilder und Grafiken anzuzeigen. Diese Fähigkeiten müssen ihnen nachträglich vom Programmierer verliehen werden. Dazu ist es erforderlich, vom gewünschten Objekt-Typ zu erben und Methoden zur Ausgabe einzufügen. Im Folgenden werden wir das am Beispiel eines Panel demonstrieren.

public class ImagePanel extends Panel {
   private Image image;

   public ImagePanel(Image image) {
      setImage(image);
   }

   public void setImage(Image image) {
      this.image = image;
      repaint();
   }

   public Dimension getPreferredSize() {
       if(image != null) {
          return new Dimension(image.getWidth(this), image.getHeight(this)));
       }
       return super.getPreferredSize();
   }

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

Dieses Panel kann in AWT-Anwendungen nun Bilder anzeigen. LayoutManager berechnen auch den Platz, den das Label im Layout benötigen wird.

Laden von Grafikdateien in Swing

In Swing haben die Java-Erfinder von Sun sehr leistungsfähige Klassen für das Einlesen von Grafikdaten aus unterschiedlichen Quellen entwickelt, die auch die Anwendung in Applets und Applikationen vereinheitlicht.


Varianten zum Einbinden von Grafiken

Viele Wege führen bekanntlich nach Rom, so auch beim erfolgreichen Laden und Anzeigen von Grafikdateien in Java.

ImageIO

javax.imageio.ImageIO ist eine sehr effiziente und einfach zu handhabende Klasse zum Laden von Grafikdateien.
Sie stellt u.a. Methoden bereit, um Bilder aus verschiedenen Quellen zu laden. So z.B. aus einer Datei, einem InputStream oder von einer URL. Ergebnis des Einlesens mit ImageIO ist immer ein Objekt vom Typ BufferedImage, welches die Klasse Image erweitert.


Laden aus einer Datei mit Angabe ihres Namens:

Image image = ImageIO.read(new File("demo.jpg"));

Diese Variante ist für das Laden von Bildern aus Dateien des lokalen Dateisystems geeignet. Z.B. mit Hilfe von JFileChooser.

Sie kommt aber nicht für die Verwendung von Applets in Frage, weil mit File-Zugriffen auf dem Client unerlaubte Operationen versucht werden würden. Sie ist also nur für den Gebrauch in Applikationen denkbar.


Laden eines Bildes aus einem InputStream:

Image image = ImageIO.read(getClass().getResource("demo.jpg"));

getClass().getResource("...") erzeugt hier einen InputStream zur Datei. Diese Variante kommt bspw. zum Einsatz, wenn sich Bilder innerhalb einer Jar-Datei befinden. Sie funktioniert aber auch, wenn die Klassen und Grafikdateien noch unverpackt im lokalen Dateisystem liegen. Man braucht also nichts mehr verändern, wenn man später aus den fertigen Klassen eine Jar-Datei erzeugt.


Laden eines Bildes in einem Package relativ zu dieser Klasse aus einem InputStream:

Image image = ImageIO.read(getClass().getResource("../images/demo.jpg"));

Es wird ein InputStream zur Datei in einer Jar-Datei erzeugt, der sie aus einem Verzeichnis relativ zu dieser Klasse läd.


Laden eines Bildes in einem Package absolut zu einer Klasse aus einem InputStream:

Image image = ImageIO.read(getClass().getResource("/de/any-domain/project/images/demo.jpg"));

Es wird ein InputStream zur Datei erzeugt, der ausgehend vom obersten Package ganz genau den Speicherort in einer Jar-Datei spezifiziert.


Laden eines Bildes im statischen Kontext:

ImageIcon icon = new ImageIcon(MyClass.class.getResource("demo.jpg"));

In einem statischen Kontext, das heißt, innerhalb einer statischen Methode, funktioniert das Ermitteln des Klassennamen mit der getClass()-Methode nicht. Hier muss der Name der Klasse als Ausgangspunkt des Pfades zum zu ladenden Bild fest verdrahtet werden. Anderenfalls wird der Compiler einen Fehler ähnlich diesem ausgeben:

MyClass.java:123: error: non-static method getClass() cannot be referenced from a static context


Laden eines Bildes von einer URL:

Image image = ImageIO.read(new URL("http://www.any-domain.de/images/demo.jpg"));

Diese Variante kommt zum Einsatz, wenn Bilder aus einem Netzwerk geladen werden sollen.


Weil dabei auch etwas schief gehen kann, muss der Abschnitt jeweils in einem try-catch - Block eingebaut werden.

Merksatz: ImageIO wird meistens dann benutzt, wenn man Grafikdateien laden und diese später selbst auf GUI-Komponenten zeichnen möchte.

ImageIcon

Objekte von ImageIcon sind zur direkten Verwendung auf Swing-GUI-Komponenten wie bspw. JButton, JLabel, JMenuItem etc. vorgesehen. Sie sind die Repräsentation von Icons oder Bildern, die auf der lokalen Festplatte, in einem Netzwerk, oder bereits im Speicher als Image-Objekt vorliegen.
javax.swing.ImageIcon ist also eine konkrete Implementierung des Icon-Interfaces, welches grundlegende Methoden für die Arbeit mit Icons oder Abbildungen definiert.
Das Laden der Bilder wird im Hintergrund bereits mit dem java.awt.Mediatracker überwacht, so dass die Bilder auf jeden Fall im Speicher sind, bevor sie gezeichnet werden.
Der Konstruktor von ImageIcon erwartet die Übergabe des Pfades zum Speicherort bzw. den Namen der zu ladenen Datei in Form eines Strings oder in Form eines Image oder einer URL. Demzufolge können Bilder aus Grafikdateien wie folgt in ImageIcon-Objekten referenziert werden:

Laden eines Bildes mit Hilfe eines vorher geladenen Image-Objektes:

JButton button = null;
ImageIcon icon = null;

try {
  Image image = ImageIO.read("demo.jpg");
  icon = new ImageIcon(image);
}
catch(IOException e) {
  e.printStackTrace();
}

button = new JButton("Demo", icon);

Diese Variante macht zur Illustration von einbettenden Komponenten (JButton, JLabel) weniger Sinn. Eleganter ist der Weg über ImageIcon.

Mehr zum Thema JButton...


Laden eines Bildes mit Hilfe der Klasse ImageIcon:

ImageIcon icon = new ImageIcon("demo.jpg");
JButton button = new JButton("Demo", icon);

Das Bild befindet sich bei diesem Beispiel in der lokalen Verzeichnisebene, im gleichen Verzeichnis dieser Klasse.


Laden eines Bildes in einem Netzwerk mit Hilfe einer URL:

ImageIcon icon = new ImageIcon(new URL("http://www.any-domain.de/images/demo.jpg"));
JButton button = new JButton("Demo", icon);


Laden eines Bildes, welches in der gleichen Jar-Datei gespeichert wurde:

ImageIcon icon = new ImageIcon(getClass().getResource("demo.jpg"));
JButton button = new JButton("Demo", icon);


Laden eines Bildes im statischen Kontext:

ImageIcon icon = new ImageIcon(MyClass.class.getResource("demo.jpg"));
JButton button = new JButton("Demo", icon);

In einem statischen Kontext, das heißt, innerhalb einer statischen Methode, funktioniert das Ermitteln des Klassennamen mit der getClass()-Methode nicht. Hier muss der Name der Klasse als Ausgangspunkt des Pfades zum zu ladenden Bild fest verdrahtet werden. Anderenfalls wird der Compiler einen Fehler ähnlich diesem ausgeben:

MyClass.java:123: error: non-static method getClass() cannot be referenced from a static context
Merksatz: Ein ImageIcon wird immer nach den Vorgaben der einbettenden Komponente (JLabel, JButton etc.) gezeichnet bzw. angeordnet. Man hat hier also weniger Einfluss auf die Darstellung.

Bilder als Hintergrund

In unserem Artikel Hintergrundbild in eine GUI einfügen erklären wir an einem Beispiel, wie man in Swing Hintergrundbilder in eine GUI oder GUI-Komponenten bekommt.

Manchmal braucht man auch die Farbe eines Pixels aus einem Bild, um eine Farbe für eine Hintergrundkomponente, bspw einen Rahmen zu bestimmen.

Laden von Bildern in JavaFX

Swing verliert nach und nach den Einfluss in der GUI-Programmierung in Java. JavaFX bietet gegenüber Swing weitaus mehr Möglichkeiten bei der Gestaltung von Benutzeroberflächen.
Auch der Code zum Einbinden von Bildern ändert sich. Das wollen wir im Folgenden anhand von Beispielen demonstrieren. (Vielen Dank an unseren Benutzer ionutbaiu für das Kapitel)

Die Änderungen zum Laden von Bildern in JavaFX gegenüber Swing bestehen in den Folgenden Punkten:

1. Es wird nun die Klasse javafx.scene.image.Image im Gegensatz zu java.awt.Image verwendet.
2. Die Image-Klasse besitzt nun verschiedene Konstruktoren, die im wesentlichen die Aufgaben der Read-Funktionen aus ImageIO ersetzen, um Bilder aus verschiedenen Quellen zu laden.

In JavaFX gibt es mehrere Möglichkeiten Bilder zu verwenden.

Bilder direkt verwenden

Um Bilder direkt zu verwenden gibt es zudem die Klasse ImageView, diese ist weitestgehend das Pendant zur Klasse ImageIcon.

1. Bild laden

Image imgIcon = new Image(getClass().getResource("icons/icon.png").toExternalForm());

2. ImageView mit Bild erstellen

ImageView imgView = new ImageView(imgIcon);

oder direkt

ImageView imgView = new ImageView(getClass().getResource("icons/icon.png").toExternalForm());

3. ImageView dem Scene-Graph hinzufügen

root.getChildren().add(imgView);

oder z.B. einem Button das Bild in Form eines Icons hinzufügen.

Button button = new Button("Button mit Bild", imgView);

Bilder als Hintergrund

Bilder können als Hintergrund eines Elements verwendet werden.

Das vorgehen hierbei ist wie folgt.

1. Bild laden

Image imgBackground = new Image(getClass().getResource("images/background.jpg").toExternalForm());

2. Bild in ein Hintergrundbild umwandeln

    BackgroundImage backgroundImage = new BackgroundImage(
                        imgBackground,
                        BackgroundRepeat.NO_REPEAT,
                        BackgroundRepeat.NO_REPEAT,
                        BackgroundPosition.DEFAULT,
                        BackgroundSize.DEFAULT);

3. Hintergrund erstellen

Background background = new Background(backgroundImage);

4. Bei der Komponente (hier root) den neuen Hintergrund setzen

root.setBackground(background);

FXML und CSS

Mit JavaFX gibt es zudem die Möglichkeit FXML und CSS einzusetzen. Hierbei kann die Oberfläche in XML definiert werden und das Aussehen mit CSS beeinflusst werden, so daß eine saubere Trennung der Zuständigkeiten möglich ist.

Eine Oberfläche mit einem Button kann mit FXML wie folgt in der Datei picture.fxml definiert werden

    <?xml version="1.0" encoding="UTF-8"?>
     
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
     
    <AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="picture.PictureController">
        <children>
            <Button fx:id="button" layoutX="10" layoutY="10" onAction="#handleButtonAction" text="Button with Icon" />        
        </children>
    </AnchorPane>

In dieser Datei ist noch nichts bezüglich der Bilder zu finden. Um nun Bilder den einzelnen Elementen zuzuweisen wird eine datei pictures.css die so aussieht verwendet.

    #AnchorPane {
        -fx-background-image: url(images/background.jpg);
        -fx-background-repeat: no-repeat;
        -fx-background-position: center center;
    }
     
    #button {
        -fx-graphic: url(icons/icon.png);
    }


Um die Verknüpfung zwischen FXML und CSS zu bekommen, haben die Elemente in der FXML Datei jeweils eine ID. (id="AnchorPane", sowie fx:id="button")

In der CSS Datei werden diese Elemente mit dem Selektor #AnchorPane und #button herausgesucht um dort das Aussehen und die Bilder zu setzen.

Um FXML- und CSS-Datei in einer Anwendung zu verbinden kann man wie folgt vorgehen:

1. View aus der FXML-Datei laden

Parent root = FXMLLoader.load(getClass().getResource("picture.fxml"));

2. Scene erstellen und View via Konstruktor zuweisen.

Scene scene = new Scene(root);

3. CSS-Stylesheet laden und der Scene hinzufügen.

scene.getStylesheets().add(getClass().getResource("picture.css").toExternalForm());

4. Anzeigen der Scene

      stage.setScene(scene);
      stage.show();

Code-Beispiele

JApplets

In Swing-Applets kann für das effiziente Einlesen von Grafikdaten die Klasse javax.imageio.ImageIO verwendet werden.
Wie einfach ihre Benutzung ist, werden wir im Anschluss demonstrieren.

Einfache JApplet-Klassen

Zeichnen auf einen Container (JPanel), welcher dem JApplet als Hintergrund hinzugefügt wird:

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


public class PictureApplet extends JApplet {
   private Image image, background;

   public void init() {
      setContentPane(new MyContentPane());

      try {
         image = ImageIO.read(new URL(getCodeBase(), "icon.png"));
         background = ImageIO.read(new URL(getCodeBase(), "/images/background.jpg"));
      }
      catch(IllegalArgumentException iae) {
	 JOptionPane.showMessageDialog(this, "Grafikdatei nicht gefunden!");
      }
      catch(IOException ioe) {
	 JOptionPane.showMessageDialog(this, "Fehler beim Einlesen der Grafikdatei!");
      }
   }

   private class MyContentPane extends JPanel {

      protected void paintComponent(Graphics g) {
         super.paintComponent(g);
         if(background != null && image != null) { //beide Bilder müssen im Speicher liegen, sonst wird nichts gezeichnet
            g.drawImage(background, 0, 0, this);
            g.drawImage(image, 10, 10, this);
         }
      }
   }
}

Link: Einbinden von Applets in HTML-Dateien

Applets in Jar-Dateien

Wenn sich das Java-Applets gemeinsam mit der zu ladenden Grafik in einer JAR-Datei zusammengefasst wurden, muss die Grafik über den ClassLoader ins Applet geladen werden.

Zeichnen auf einen Container (JPanel), welcher dem JApplet als Hintergrund hinzugefügt wird:

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


public class PictureApplet extends JApplet {
   private Image image, background;

   public void init() {
      setContentPane(new MyContentPane());

      try {
         image = ImageIO.read(getClass().getResource("icon.png"));
         background = ImageIO.read(getClass().getResource("images/background.jpg"));
      }
      catch(IllegalArgumentException iae) {
	 JOptionPane.showMessageDialog(this, "Grafikdatei nicht gefunden!");
      }
      catch(IOException ioe) {
	 JOptionPane.showMessageDialog(this, "Fehler beim Einlesen der Grafikdatei!");
      }
   }

   private class MyContentPane extends JPanel {

      protected void paintComponent(Graphics g) {
         super.paintComponent(g);
         if(background != null && image != null) { //beide Bilder müssen im Speicher liegen, sonst wird nichts gezeichnet
            g.drawImage(background, 0, 0, this);
            g.drawImage(image, 10, 10, this);
         }
      }
   }
}

Das Applet-Tag in der HTML-Datei muss jetzt angepasst werden, damit der Browser weiß, wo sich das Applet befindet.
Link: Einbinden von Applets in HTML-Dateien für Jar-Dateien

Swing-Applikationen

Auch Swing-Applikationen werden im Allgemeinen in Jar-Archiven zusammengefasst. Diese lassen sich auf jedem System per Doppelklick starten, oder per Webstart über das Internet laden.
Hier also nun die Variante für eine Applikation. Auffällig ist, dass sich der Code des Panels gegenüber dem Applet nur leicht, der Code zum Laden der Bilder aber gar nicht verändert hat.

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

public class PicturePanel extends JPanel { 
   private Image image, background;
 
   public PicturePanel() {
      super(new GridBagLayout());

      try {
         image = ImageIO.read(getClass().getResource("icons/icon.png"));
         background = ImageIO.read(getClass().getResource("images/background.jpg"));
      }
      catch(IllegalArgumentException iae) {
         JOptionPane.showMessageDialog(this, "Grafikdatei nicht gefunden!\n"+iae.getMessage());
      }
      catch(IOException ioe) {
         JOptionPane.showMessageDialog(this, "Fehler beim Einlesen einer Grafikdatei!\n"+ioe.getMessage());
      }

      JButton pictureButton = new JButton("Button mit Icon", new ImageIcon(image));
      add(pictureButton);
   }
 
   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if(background != null) { //Bild muss im Speicher liegen, sonst wird nichts gezeichnet
         g.drawImage(background, 0, 0, this);
      }
   }
}

Das Ganze kann nun in einem Fenster angezeigt werden:

import javax.swing.*;

public class PictureFrame {
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        JFrame f = new JFrame("Bildbetrachter");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new PicturePanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    });
  }
}

JavaFX-Applikationen

Wenn man sich nun den Code einer entsprechenden JavaFX-Anwendung ansieht, könnte man meinen, dass es scheinbar Parallelen zu AWT und Swing gibt. Java-FX-Klassen haben nun kein vorangestelltes "J" mehr und die Initialisierung eines javafx.scene.control.Button sieht aus, wie bei einem Swing-JButton. Allerdings gibt es auch Neues, wie nun gezeigt wird:

import java.io.PrintWriter;
import java.io.StringWriter;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundImage;
import javafx.scene.layout.BackgroundPosition;
import javafx.scene.layout.BackgroundRepeat;
import javafx.scene.layout.BackgroundSize;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Picture extends Application {

    @Override
    public void start(Stage primaryStage) {

        try {
            Image imgBackground = new Image(getClass().getResource("images/background.jpg").toExternalForm());
            BackgroundImage backgroundImage = new BackgroundImage(
                    imgBackground,
                    BackgroundRepeat.NO_REPEAT,
                    BackgroundRepeat.NO_REPEAT,
                    BackgroundPosition.DEFAULT,
                    BackgroundSize.DEFAULT);
            Background background = new Background(backgroundImage);

            Image imgIcon = new Image(getClass().getResource("icons/icon.png").toExternalForm());
            ImageView imgView = new ImageView(imgIcon);

            Button btn = new Button("Button mit Icon", imgView);
            btn.setText("Button mit Icon");

            StackPane root = new StackPane();
            root.getChildren().add(btn);
            root.setBackground(background);

            Scene scene = new Scene(root, 300, 250);

            primaryStage.setTitle("Bildbetrachter FX");
            primaryStage.setScene(scene);
            primaryStage.show();

        } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("Fehler");

            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);

            alert.setContentText(sw.toString());

            alert.showAndWait();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Grafiken aus externen Jar-Dateien laden

Im Internet sind reichlich freie Quellen zu finden, die spezielle Grafiken (Icons) für die visuelle Kennzeichnung und Verschönerung von GUI-Elementen eingesetzt werden können.
Diese Quellen liegen meist in gepackter Form als Zip-Archiv vor. Um sie für ein Java-Programm nutzbar zu machen, kann man eine solche Zip-Datei einfach in eine Jar-Datei umbenennen (Datei-Suffix ändern) oder auch, unter Beachtung der Lizenz, einzelne Dateien extrahieren und in eine neue Jar-Datei packen. Den Weg, Grafikdateien aus der Jar-Datei zu laden, die auch unser Programm enthält, haben wir bereits oben gesehen. Wir werden uns nun aber mal ansehen, wie Grafikdateien aus externen Bibliotheken bzw. Archiven geladen werden können.


Bibliotheken im Classpath

(Artikel noch einzufügen)


Bibliotheken außerhalb des Classpaths

Um Grafikdateien aus einer externen Jar-Datei zu laden, die sich nicht im Sichtbarkeitsbereich des ClassLoaders befindet, kann man den absoluten Pfad zur Jar-Datei entsprechend nach folgendem Schema zusammenbauen:

jar:protocol//:path/to/jarfile/jarfile.jar!/my/package

protocol bezeichnet hier z.B. http oder file. Direkt nach der Jar-Datei folgt ein Ausrufezeichen. Was danach folgt ist der Pfad innerhalb der Jar-Datei, also die einzelnen Packages.

URL jarPath = new URL("jar:file://pfad/zur/jardatei/MeinProgramm.jar!/bilder/bild.jpg");

/bilder/bild.jpg bezeichnet hierbei den Pfad innerhalb der externen Jar-Datei zur Grafikdatei.


Fragen

Das Thema wurde nicht ausreichend behandelt? Du hast Fragen dazu und brauchst weitere Informationen? Lass Dir von uns helfen!

Wir helfen dir gerne!


Dir hat dieser Artikel gefallen? Oder Du hast Fehler entdeckt und möchtest zur Berichtigung beitragen? Prima! Schreibe einen Kommentar!

Du musst angemeldet sein, um einen Kommentar abzugeben.