Hintergrundbild in JFrame, die hunderste ;)

Status
Nicht offen für weitere Antworten.

hdi

Top Contributor
Hey, ich tick so aus mit diesem Spamschutz, ich hock manchmal 5 minuten da er verweigert mir ALLES :x boah, also ^^

Thema: Hintergrundbild in JFrame

ich weiss das wurde schon so oft gefragt... Aber es gibt hier tausend Antworten dazu, und jede ist anders. Der eine nutzt irgendwelche MediaTracker, der andere IOStreams, etc. Und irgendwie is das immer nur an nem Beispielbild, meist
irgendwo im Internet. Ich verstehe bei all diesen Beispielen noch immer nicht, was denn das Konzept dahinter ist..

Ich hab mir paar Threads angeschaut, und es dann versucht:

Code:
		// setup loading window
		final JFrame loadingFrame = new JFrame("Loading...");
		loadingFrame.setUndecorated(true);

		// setup panel
		JPanel panel = new JPanel() {
			@Override
			public void paintComponent(Graphics g) {

				// refresh
				super.paintComponent(g);
				// load background picture...
				BufferedImage backgroundPic = null;
				try {
					backgroundPic = ImageIO.read(loadingFrame.getClass()
							.getResourceAsStream("/images/loading.jpg"));

				} catch (IOException e) {
					e.printStackTrace();
				}
				// ...and draw it
				g.drawImage(backgroundPic, 0, 0, 200, 100, this);
			}
		};

              // hier adde ich dann das panel und mach das fenster sichtbar

Das gibt nun leider beim Ausführen folgende Exception:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(Unknown Source)
at controller.StartUp$1.paintComponent(StartUp.java:33)

Mein bild ist im projekt-ordner "images", und der oben genannte Code ist in einer Klasse im projet-ornder "src".
Also ich versteh das alles nicht, wäre toll wenn mir jemand mal etwas allgemeiner erklären könnte, wie das ist mit Bildern und jar-Files... Danke
 

hdi

Top Contributor
ich push mal, das mach ich nur weil mein thread-titel aus spamschutz gründen erst "click for more" heissen musste.
und ich denk mir mal, auf so nen thread klickt verständlicherweise keiner ;)
 

Quaxli

Top Contributor
Der erste / muß weg, also ("images/loading.jpg") und der Ordner images sollte ein Unterordner in dem Verzeichnis sein, in dem Deine class-Dateien liegen.

Außerdem ist der ImageIO.read(..) an der falschen Stelle. Es sollte zwar funktionieren, aber bei jedem Neuzeichnen wird das Bild wieder erneut gelesen. Du sollstest das daher woanders hin packen, z. B. in den Konstruktor des JPanel.

<edit>
Eben erst gesehen: Die Referenz auf den loadingFrame sollte auch unnötig sein, also
backgroundPic = ImageIO.read(getClass().getClassLoader().getResourceAsStream("images/loading.jpg"));
</edit>
 

André Uhres

Top Contributor
Quaxli hat gesagt.:
Der erste / muß weg, also ("images/loading.jpg")
Wenn wir es so machen, wie ich oben vorgeschlagen habe, dann muss das erste / bleiben:
das Bild liegt ja dann nicht in einem Unterverzeichnis, sondern in einem "parallelen" Verzeichnis :wink:
 

Murray

Top Contributor
André Uhres hat gesagt.:
Quaxli hat gesagt.:
Der erste / muß weg, also ("images/loading.jpg")
Wenn wir es so machen, wie ich oben vorgeschlagen habe, dann muss das erste / bleiben:
das Bild liegt ja dann nicht in einem Unterverzeichnis, sondern in einem "parallelen" Verzeichnis :wink:
Müsste es in dem Fall nicht "../images/loading.jpeg" sein?
 

Quaxli

Top Contributor
André Uhres hat gesagt.:
Quaxli hat gesagt.:
Der erste / muß weg, also ("images/loading.jpg")
Wenn wir es so machen, wie ich oben vorgeschlagen habe, dann muss das erste / bleiben:
das Bild liegt ja dann nicht in einem Unterverzeichnis, sondern in einem "parallelen" Verzeichnis :wink:

O.k. wieder was gelernt... ;) Ich packe es immer bei den class-Dateien mir rein, weil das für mich persönlich vom organisatorischen logischer erscheint.
 
S

SlaterB

Gast
Offtopic:
André Uhres hat gesagt.:
Ich gehe übrigens regelmässig die "Unbeantworteten Beiträge" durch.
Von daher ist es in meinen Augen eher ein Nachteil, wenn man seinen Beitrag "pushed":
den finde ich ja dann dort nicht mehr!
http://www.java-forum.org/de/search.php?search_id=unanswered
ich wünschte, wir hätten ein Java-Forum mit individuell programmierbaren Funktionen,
z.B. eine Status-Betrachtung, die Folgepostings des Erstposters ignoriert,
die überhaupt unabhängig von der Anzahl der Postings ist,
wo User bei der Antwort mitangegeben können, ob sie das Thema im weiteren verfolgen werden, bereits zu 100% beantwortet haben,
oder nur einen Hinweis geben und es im Grunde immer noch ganz offen ist,

bei manchen Topics verkneife ich mir auch manchmal einen kleinen Hinweis, weil ich weiß, dass dann viel weniger andere reinschauen, da es aus der Liste fällt
 

hdi

Top Contributor
Super, danke :)

Nochmal zu dem Push: Ich habe noch nie einen einzigen Beitrag gepusht, ich mag das auch nicht. Es ist eh
schon cool genug, dass hier Leute freiwillig helfen, so ein "push" ist einfach frech.

Ich habs wie gesagt nur gemacht, weil ich so einen dummen Titel wählen musste, und wenn ich hier ein Helfer
wär und ich würd nen Thread sehen "Click for more" dann würd ich mir denken ja leck mich doch xD
 

hdi

Top Contributor
Sry, muss mich nochmal melden, da ich wieder ein Problem habe.

Ich wollte jetzt alle Bilder beim Programmstart vorladen. Dafür hab ich mir ne Klasse gemacht die alle Bilder
als statische Objekte hält, und eine Methode anbietet um die Bilder zu initialisieren:

Code:
public class ImgDB {

	public static BufferedImage background;
	public static BufferedImage ball;

	public static List<BufferedImage> images;
	public static List<String> paths;

	public static void init() {

		images = new ArrayList<BufferedImage>();
		paths = new ArrayList<String>();

		init(background, "/images/background.jpg");
		init(background, "/images/ball.jpg");

	}

	private static void init(BufferedImage image, String path) {

		images.add(image);
		paths.add(path);
	}

	public static String loadNext() {

		String imagePath = null;
		for (int i = 0; i < images.size(); i++) {
			BufferedImage image = images.get(i);
			if (image == null) {
				imagePath = paths.get(i);
				try {
					image = ImageIO.read(new File(imagePath));
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println("Fehler beim laden von "+imagePath);
				}
			}
			break;
		}
		return imagePath;
	}
}

Beim Start wird jetzt loadNext() aufgerufen, solange es einen gültigen String (!= null) zurückliefert.

Jetzt komm ich zum Problem: Den o.g. Code mit getClass() kann ich nicht mehr verwenden, weil ich hier
in einem statischen Kontext bin. Ich habs wie man sieht mit File versucht, aber er findet die Bilder nicht,
ich krieg immer diese Meldung "Fehler beim laden von...".

An den Ordnern oder so hab ich nix verändert, d.h. es gilt noch immer das, was ich oben sagte.

Wie mach ich das jetzt?

Es ist wie gesagt sehr wichtig, dass die Bilder später dann im jar richtig integriert sind und sie bei allen Leuten angezeigt werden!
 

Murray

Top Contributor
Du kannst irgendein Class-Object verwenden, solange es aus Deinem Jar-File gelandet wird. Insofern sollte folgendes gehen (auch in statischen Methode):
Code:
ImageIO.read( ImgDB.class..getResourceAsStream( pfadZurDatei));
 

Quaxli

Top Contributor
Das klingt vielleicht jetzt blöd, aber dann laß' den statischen Kontext halt weg. Die Idee von einer Klasse als "ImageLib" ist prinzipiell eine gute Idee.
Ich vermute Du hast das Ganze statische konzipiert, um problemlos darauf zugreifen zu können? Wenn dem so ist, gibt es eine einfache Lösung: Konzipiere die Klasse als Singelton

Hier mal einBeispiel aus dem Javabuch von Guido Krüger (www.javabuch.de):

Code:
public class SpriteLib{
  private static SpriteLib instance = null;

  public static Singleton getInstance(){
    if (instance == null) {
      instance = new Singleton();
    }
    return instance;
  }

  private Singleton(){
  
  }
}

Damit hättest Du eine "ganz normale Klasse" ohne den statischen Kontext und könntest die Bilder über ImageIO.getClass().... laden.
Die Instanz holst Du dann nicht mit

SpriteLib abc = new SpriteLib(),

sondern mit

SpriteLib abc = SpriteLib.getInstance();

Hier nochmal als Beispiel meine persönliche SpriteLib, die ich so verwende, sie ist etwas aufgeblähter, als das, was Du brauchst, aber vielleicht wird das Konzept deutlicher:

Code:
package sprite;

import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import javax.imageio.ImageIO;

public class SpriteLib {

	private static SpriteLib single;
	private static GraphicsEnvironment ge;
	private static GraphicsConfiguration gc;
	private static HashMap<URL, BufferedImage> sprites;

	public static SpriteLib getInstance() {
		if (single == null) {
			single = new SpriteLib();
		}
		return single;
	}

	private SpriteLib() {
		//GraphicsConfiguration für VolatileImage
		ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
		
		sprites = new HashMap<URL, BufferedImage>();
	}

	public BufferedImage getSprite(String path) {

		BufferedImage pic = null;
		URL location = getURLfromRessource(path);

		pic = (BufferedImage) sprites.get(location);

		if (pic != null) {
			return pic;
		}

		try {
			pic = ImageIO.read(location); // Über ImageIO die GIF lesen
		} catch (IOException e1) {
			System.out.println("Fehler beim Image laden: " + e1);
			return null;
		}

		BufferedImage better = gc.createCompatibleImage(pic.getWidth(), pic.getHeight(), Transparency.BITMASK);
		Graphics g = better.getGraphics();
		g.drawImage(pic, 0, 0, null);
		g.dispose();
		
		sprites.put(location, better);

		return better;
	}

	public BufferedImage[] getSprite(String path, int column, int row) {

		URL location = getURLfromRessource(path);

		BufferedImage source = null;

		source = (BufferedImage) sprites.get(location);

		if (source == null) {
			try {
				source = ImageIO.read(location); // Über ImageIO die GIF lesen
			} catch (IOException e1) {
				System.out.println(e1);
				return null;
			}

			sprites.put(location, source);

		}
		
		BufferedImage better = gc.createCompatibleImage(source.getWidth(), source.getHeight(), Transparency.BITMASK);
		Graphics g = better.getGraphics();
		g.drawImage(source, 0, 0, null);
		g.dispose();

		int width = source.getWidth() / column;
		int height = source.getHeight() / row;

		BufferedImage[] pics = new BufferedImage[column * row];
		int count = 0;

		for (int n = 0; n < row; n++) {
			for (int i = 0; i < column; i++) {
				pics[count] = source.getSubimage(i * width, n * height, width, height);
				count++;
			}
		}

		return pics;

	}

	public URL getURLfromRessource(String path) {
		return getClass().getClassLoader().getResource(path);
	}

}

<edit>
Wie schon mal erwähnt liegt der Image-Ordner bei mir immer im Verzeichnis, in dem die class-Dateien sind. Das Beispiel ist darauf ausgelegt. Ich bin nicht 100% sicher, ob es mit einer anderen Herangehensweise funktioniert.
</edit>
 

hdi

Top Contributor
Danke euch, die Sprite Klasse werde ich mir mal "ausleihen" xD Sprites soll mein Game ja später auch haben, ich hab noch nie was mit Sprites gemacht und ich denke dein Code ist während ich mir das beibring sehr nützlich.

Aber b2t, ich habn Problem und verstehe es nicht.

Es tritt in dieser Methode auf:

Code:
	public static String loadNext() {

		String imagePath = null;
		for (int i = 0; i < images.size(); i++) {
			BufferedImage image = images.get(i);
			if (image == null) {
				System.out.println("image was null");
				imagePath = paths.get(i);
				try {
					image = ImageIO.read(ImageLibrary.class
							.getResourceAsStream(imagePath));
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println("Fehler beim Laden von Image "+imagePath);
				}
			}
			break;
		}
		return imagePath;
	}

Und zwar lädt er jetzt die Bilder richtig, denn ich bekomme die System.out.println-Meldungen nicht mehr.

Allerdings, jedesmal wenn diese Methode aufgerufen wird, gibt die Prüfung

Code:
if (image == null)

ein true zurück. Eigentlich sollte ja nach dem ersten Aufruf der Methode das erste Image initialisiert sein, d.h.
wenn die Methode zum zweiten mal aufgerufen wird, müsste für images.get(0) ja image != null sein...

Es läuft im Endlosloop. Ich dachte sponstan an ein call by value problem, aber es is doch eindeutig call by reference, also müsste das doch okay sein... Check ich grad nicht
 

Marco13

Top Contributor
Quaxli hat gesagt.:
Hier mal einBeispiel aus dem Javabuch von Guido Krüger (www.javabuch.de):

Code:
...
  public static Singleton getInstance(){
    if (instance == null) {
      instance = new Singleton();
    }
    return instance;
  }
...

:shock: IMHO sollte die Methode synchronized sein ...

Was diese Klasse dann für einen Zweck erfüllen soll, ist mir aber nicht klar: Wozu sollen die Bilder vorgeladen werden? (Also, an welcher Stelle, und warum nicht genau da, wo sie gebraucht werden?)
 

Quaxli

Top Contributor
Nö, das ist schon für Bilder auch zweckmäßig. Wenn Du das böse Feindraumschiff (oder was auch immer) abgeknallt hast, erzeugt man ja meist das nächste (oder die nächsten Fünf ;) ) mit gleichem Bild. Und damit man das Bild nicht jedes Mal laden muß, packe ich es in meine SpriteLib und ziehe es dann dort raus.

In die SpriteLib lade ich die Bilder einmal beim Starten des Spiels um dann für jedes neue Sprite bzw. bei einem Neustart (nach GameOver) die Bilder dort abzuholen.

@Marco13:
Neue Ideen sind natürlich willkommen :)
 

hdi

Top Contributor
Ja okay, aber wieso funktioniert das jetz nicht mit meiner loadNext() Methode? Wieso bleibt das immer null...
 

hdi

Top Contributor
das mach ich ja, ich glaub ich hab die ganze klasse im ersten post gepostet.
egal, hier nochmal die ganze ImageLibrary:

Code:
public class ImageLibrary {

	public static BufferedImage loading;
	public static BufferedImage background;
	public static BufferedImage ball;

	public static List<BufferedImage> images;
	public static List<String> paths;

	public static void init() {

		images = new ArrayList<BufferedImage>();
		paths = new ArrayList<String>();

		init(loading, "/images/loading.jpg");
		init(background, "/images/background.jpg");
		init(background, "/images/ball.jpg");
	}

	private static void init(BufferedImage image, String path) {

		images.add(image);
		paths.add(path);
	}

	public static String loadNext() {
		String imagePath = null;
		for (int i = 0; i < images.size(); i++) {
			BufferedImage image = images.get(i);
			if (image == null) {
				System.out.println("image == null an in der liste an stelle " + i);
				imagePath = paths.get(i);
				try {
					image = ImageIO.read(ImageLibrary.class
							.getResourceAsStream(imagePath));
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println("Fehler beim Laden von Image "
							+ imagePath);
				}
			}
			break;
		}
		return imagePath;
	}
}

und beim Programmstart mach ich in der main methode folgendes:

Code:
ImageLibrary.init();
while (ImageLibrary.loadNext() != null);

Als Ausgabe erhalte ich dann in einer Endlosschleife die Meldung, die ich in die loadNext() Methode eingebaut habe:

image == null an in der liste an stelle 0

und wie bereits gesagt, müsste ja beim zweiten aufruf der Methode loadNext() das image an stelle 0 in der liste, in diesem fall das BufferedImage "background", eben nicht null sein, weil es im aufruf zuvor initialisiert wurde.

wer sich fragt wieso ich das in so einer schleife mache: ich nehm in der main-methode eigentlich den rückgabewert um ihn als string in einem ladebildschirm anzuzeigen.
 

Murray

Top Contributor
hdi hat gesagt.:
das mach ich ja, ich glaub ich hab die ganze klasse im ersten post gepostet.
Wo machst Du das?

Für mich sieht das eher so aus:
Code:
Image image = images.get( wasAuchImmer);
if ( image != null) {
  //-- Treffer, alles gut
} else {
 //--- image in der Liste noch nicht vorhanden
 image = machIrgendwas(); //--- jetzt wird die lokale Variable image zwar initialisiert, aber 
                                         //--- am Inhalt von images aendert sich nichts
}

Durch das erneute Zuweisen der lokalen Variable image kommt das Image-Objekt noch lange nicht in die Liste.
 

hdi

Top Contributor
Ahh Moment, ich glaub ich habs jetzt überrissen:

Ich dachte mir:

BufferedImage image = images.get(i)

ist ja nur ein Verweis auf das statische Objekt "background", und das ist ja auch völlig korrekt!

Aber dann:

image = ImageIO.read()

und diese Methode erstellt wohl ein neues Objekt.
Damit hab ich jetzt die lokale Variable image, die vorher noch ein Verweis auf background war, überschrieben!

Ist das richtig? Ich denk schon, klingt zumindest logisch.

Ich muss jetz aber versuchen das ganze umzubauen, weil es ist ja nich gerade toll, 2 Listen von Images zu haben, eine, die nur nicht initialisierte Rohlinge enthält, die eigentlich eh verworfen werden, und eine mit den echten.

Ich muss da ne eindeutige Ordnung reinbringen, sodass nicht alles falsch zugewiesen wird wenn man
mal zufällig 2 Zeilen vertauscht bei der internen init() Methode, weil es dann am Ende falsch zugewiesen wird.

Okay aber ich habs jetzt verstanden :) Danke schön
 

hdi

Top Contributor
Ach... noch ne kleine Design-Frage:

Ich möchte gerne während diesem Vorladen einen kleinen Lade-Screen zeigen, der anzeigt was grad passiert, also sowas wie "loading images/alien.jpg" oder "connecting to server" etc etc.

Um das zu realisieren konnte ich das jetzt nur so machen, dass ich der ImageLibrary selber ein JLabel geb, das halt auf diesem LadeScreen liegt, und er setzt dann den Text:

Code:
public class ImageLibrary {

	public static BufferedImage background;
	public static BufferedImage ball;

	public static void loadAndDisplay(JLabel monitor) {

		cache(background, "/images/background.jpg", monitor);
		cache(ball, "/images/ball.jpg", monitor);
	}

	private static void cache(BufferedImage img, String path, JLabel monitor) {

		monitor.setText("Precaching " + path);
		try {
			img = ImageIO.read(ImageLibrary.class.getResourceAsStream(path));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Aber das gefällt mir gar nicht :( In Sachen Design halt ich mich generell ganz gerne tagelang auf, aber ich find irgendwie das is das wichtigste, wenn man Programmieren lernt, dass man lernt, gut zu designen. Ich meine zum Laufen bringt man es i.d.R. IMMER, die Frage ist wie beschissen der Code danach aussieht.

Und dass eine Bibliothekt, die eigentlich nur statische Bilder anbietet, jetz irgendwas mit nem JLabel macht, find ich halt kacke.

Aber anders konnte ich es bisher nicht lösen. Habt ihr da n Vorschlag?
 

Murray

Top Contributor
Du könntest z.B. ein Interface definieren, von dem der Verwender der Library dann eine eigene Implementierung in die Library-Methoden hineinreicht:
Code:
public class ImageLibrary {

   public interface StatusCallback {
      public void setStatusText( String msg);
      public void handleError( Throwable t);
   }


   public static BufferedImage background;
   public static BufferedImage ball;

   public static void loadAndDisplay( StatusCallback monitor) {

      cache(background, "/images/background.jpg", monitor);
      cache(ball, "/images/ball.jpg", monitor);
   }

   private static void cache(BufferedImage img, String path, StatusCallback monitor) {

      monitor.setStatusText("Precaching " + path);
      try {
         img = ImageIO.read(ImageLibrary.class.getResourceAsStream(path));
      } catch (IOException e) {
         monitor.handleError( e);
      }
   }
}


Und der Verwender der Library würde das dann implementieren, z.B. mit einer anonymous inner class:

Code:
finalJLabel statusLabel = ....;
final JLabel errorLabel = ....;
...
ImageLibrary.loadAndDisplay( new ImageLibrary.StatusCallback() {
      public void setStatusText( String msg) {
         statusLabel.setText( msg);
      };
      public void handleError( Throwable t) {
         errorLabel.setText( t.toString());
         t.printStackTrace();
      }
});
 

hdi

Top Contributor
edit
sry ich schweife ab. Danke für die Hilfe ich kriegs irgendwie nicht hin aber das langweilt mich jetz alles, ich mach das jetz so wie ichs eigentlich nicht möchte. Was soll ich sagen, es ist zu schwer für mich, ich kann mein Problem nicht mal ausdrücken.

Das einzige, was ich nochmal wissen möchte, ob der folgende Code wirklich das Bild erstellt, sodass ich danach einfach per ImageLibrary.background drauf zu greifen kann und es auch wirklich das Bild anzeigt:

Code:
public class ImageLibrary {

   public static BufferedImage background;

   public static void init() {

      cache(background, "/images/background.jpg");
   }

   private static void cache(BufferedImage img, String path) {

      try {
         img = ImageIO.read(ImageLibrary.class.getResourceAsStream(path));
      } catch (IOException e) {
      }
   }
}

Weil ich check inzwischen gar nix mehr, die absoluten Grundlagen von Objekt-Referenzen etc entziehen sich mir grad.

Nochmal danke !
 

Murray

Top Contributor
Nein, der Code macht nicht, was Du willst. In der cache-Methode wird lediglich dem Parameter img (also prinzipiell einer lokalen Variablen) ein neuer Wert zugewiesen. Mit einem Array würde es aber funktionieren:
Code:
public class ImageLibrary {

   public static final String[] imgNames = new String{ "/images/background.jpg", "/images/whatever.gif"};
   public static BufferedImage[] imgs = new BufferedImage[ imgNames.length];

   public static void init() {

      for (int i=0; i<imgNames.length; i++) cache( i);
   }

   private static void cache( final int idx) {

      try {
         imgs[i] = ImageIO.read(ImageLibrary.class.getResourceAsStream(imgNames[i]));
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}
 

hdi

Top Contributor
Moment mal. Ich glaub es ist euch wieder nicht ganz klar, wo mein Problem liegt. Ich entschuldige mich dafür dass ich mich hier einfach nicht richtig ausdrücken kann, wie es scheint. Aber ich denke ich kann es jetzt gut formulieren.

Schau mal: Sobald ich anfange, irgendwas in einer Schleife zu machen, oder eine Kapselungs-Funktion zu schreiben,
(wie zB meine Funktion "cache()" im Beispiel über deinem Post), habe ich ja das Problem, dass ich dann innerhalb dieser Schleife/Funtkion ein neues lokales Objekt erstelle, wenn ich etwas per ImageIO.read lade.

Klar kann ich dieses Objekt nun abspeichern, damit es mir nicht verloren geht. zB in einem array, das hast du ja gemacht mit dem array "imgs".

Aber man muss sich nochmal klar werden, was überhaupt diese Klasse ImageLibrary ist:

Sie soll öffentliche, statische Image-Objekte bereitstellen, damit ich später zB irgendwo im Spiel zB einem Objekt eine Textur zuweisen kann, die ich mittels ImageLibrary.eineTextur holen kann.

Gut, zurück zu deinem Beispiel: Jetzt hab ich Image-Objekte, die auch tatsächlich die Bild-Infos enthalten, in einem array "imgs". Und nun? Verstehst du, der Witz ist, ich kann mir ImageObjekte erstellen und abspeichern, wie ich lustig bin. Fakt ist, ich werde sie niemals an die statischen Objekte binden können. Wie denn, innerhalb der Schleife/Funktion weiss ich nicht, für welches statische Image-Objekt ich eigentlich grad ein Image erstelle...
(Ist klar, was ich damit meine?)

Die einzige Möglichkeit, um wirklich meine Bilder zu initialisieren, sodass ich später auch drauf zugreifen kann, scheint es zu sein, explizit den statischen Objekten das zuzuweisen:

Code:
public class ImageLibrary{

public static BufferedImage bild1, bild2, bild3, ...

public void init(){

try{
bild 1 = ImageIO.read ( class.getRessourceAsStream ("/images/bild1.jpg");
}
catch (...) {}
try{
bild 2 = ImageIO.read ( class.getRessourceAsStream ("/images/bild2.jpg");
}
catch (..) {}
...
}

}

Gut, aber genau das möchte ich nicht, und ich will hier lediglich herausfinden, ob es die einzige Möglichkeit ist, die ich habe. JEtzt die Frage: Warum möchte ich das nicht?

Antwort: Man kann sich denken dass bei ca 30-50 Bildern, die mein Spiel insgesamt haben wird, diese init() Methode sehr unflexible und unübersichtlich ist. Das ist das eine, das ist mehr eine Sache der Übersichtlichkeit, man hat halt dann 50 try-catch Blöcke. (Alle Anweisungen in einen Block zu packen wäre schlecht, denn sobald ein Bild nicht gefunden wird bricht er ab)

Zum zweiten, wer sich erinnert, wollte ich ja auf einem Bildschirm anzeigen, welches Image gerade geladen wird.
D.h. ich müsste die init() Methode oben erweitern:

Code:
public void init(){

someLabel. setText ("Loading "/images/bild1.jpg");
try{
bild 1 = ImageIO.read ( class.getRessourceAsStream ("/images/bild1.jpg");
}
catch (...) {}
}

Ok. Und bei sowas, wenn man 50 mal immmer das gleiche tut quasi, ist es doch normale Programmierer-Routine, sich dafür ne Kapselungs-Methode zu schreiben, am besten aber ne Schleife. Doch schon mit der Methode geht es nicht, wie du ja grad sagtest (ich rede von der Methode "cache()" oben)

Also... ich hoffe, ich konnte mich endlich korrekt ausdrücken. Ich sehe keinen anderen Weg als diese hässliche, ellenlange, unübersichtliche init() Methode zu schreiben, was ja mal elendig schlechter Programmierstil ist, weil es sowas ist wie:

Code:
array[0] = 10;
array[1] = 20;
array[2] = 30;
...noch 50 mal...

statt:

Code:
int x = 0;
for( int i = 0; i<array.length; i++){
      x += 10;
      array[i] = x;
}

Und DAS ist es, was mich so nervt :?
 

Murray

Top Contributor
hdi hat gesagt.:
Sie soll öffentliche, statische Image-Objekte bereitstellen, damit ich später zB irgendwo im Spiel zB einem Objekt eine Textur zuweisen kann, die ich mittels ImageLibrary.eineTextur holen kann.

Wenn Du zur Speicherung (wie im Beispiel) ein Array verwendest, dann müsste es für den Verwender natürlich eine Methode ImageLibraray.getImage( int imgIdx) geben (über statische Variablen in der Klasse geht das dann nicht). Und sinnvollerweise würde man dann in der ImageLibrary noch public static final int-Konstanten definieren, die der Verwender dann benutzt.

Unschön daran: es gibt eine Redundanz zwischen dem Aufbau des Arrays mit den Dateinamen und den Konstanten in der Library; das ist eine Fehlerquelle (aber immerhin nur auf der Seite der Library).

Alternativ könnte man auch anstelle des Arrays eine HashMap zur Speicherung verwenden, die Keys als Konstanten zur Verfügung stellen und in der init-Methode zu allen Keys das vorgeladene Bild in der HashMap ablegen. Aber auch da gibt es noch eine gewisse Redundanz in der Library.

Das, was Du eigentlich willst, könnte man mit Annotations erreichen.
 

hdi

Top Contributor
Redundanz, hätte ich dieses Wort in meinem Wortschatz gehabt, wäre euch glaub ich schneller klargeworden, was mein Problem ist ;) Genau das ist es, was ich vermeiden will. Ich arbeite halt nicht alleine sondern mit einem Freund über SVN, und so Dinge können dann da schnell zu Fehlern führen wenn er zufällig 2 Zeilen vertauscht, unwissend davon dass das tödlich ist für das korrekte Binden der ImageDateien an die Objekte..

Auch Hashmaps hab ich schon versucht, leider Gottes muss ich innerhalb einer Schleife sowohl auf das Objekt als auch den Key zugreifen, um die beiden miteinander in einem ImageIO.read-Aufruf aneinenader zu binden:

Code:
getObject = ImagIO.read.. (getKey);

Was ja nicht geht, ich dachte erst es geht doch über keySet() und values(), aber das keySet gibt er einem irgendwie nicht georndet sondern durcheinander gewürfelt, und damit kann ich alles wieder wegwerfen.

Gut, also zu Annotations: Davon hab ich schon gehört, weiss aber nicht was das ist. Aber ich schöpfe neue Hoffnung, dass mein mein Problem doch schön und weniger fehleranfällig lösen kann.

Ich werd jetz mal danach Googlen, so far & tausend Dank

edit:

jo okay, also..ich muss sagen ich überreiss das nicht ganz. Hab mir auf der Sun Seite und in Java-Insel das durchgelesen, und irgendwie weiss ich grad nich so ganz was das jetzt mit meiner ImageLibrary zu tun hat,bzw. wie ich die Annotation schreiben soll. Was kommt da rein? Sowas wie

Code:
public @Interface LibraryElement(

      String path()
)

? Also ich weiss nich... Bräcuthe da bitte noch Hilfe, ich seh diese Annotations wie gesagt zum ersten mal
 

Murray

Top Contributor
Mit der Hashmap könnte es so aussehen:
Code:
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;

import javax.imageio.ImageIO;


public class ImageLibrary {
	
	public static final String background = "/images/background.jpg";
	public static final String foreground = "/images/foreground.jpg";
	public static final String whatever   = "/images/whatever.jpg";
	
	private static final HashMap<String,BufferedImage> imgs;  

	//--- statt vom Verwender explizit aufzurufender Init-Methode lieber den 
	//--- Class-Initializer verwenden
	static  {
		imgs = new HashMap<String,BufferedImage>();

		cache( background);
		cache( foreground);
		cache( whatever);
	}
	
	private static void cache( String path) {
		
		try {
			imgs.put( path, ImageIO.read(ImageLibrary.class.getResourceAsStream( path)));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public BufferedImage get( String path) {
		return imgs.get( path);
	}
}
 

Murray

Top Contributor
Und noch eine Möglichkeit (redundanzfrei und typsicher):
Code:
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;


public class ImageLibrary {
	
	public static class ImgWrapper {
		final BufferedImage img;
		
		private ImgWrapper( final String path) {
			BufferedImage img = null;
			try {
				img = ImageIO.read(ImageLibrary.class.getResourceAsStream( path));
			} catch ( IOException e) {
				e.printStackTrace();
			}
			this.img = img;
		}
	}
	
	public static final ImgWrapper background = new ImgWrapper( "/images/background.jpg");
	public static final ImgWrapper foreground = new ImgWrapper( "/images/foreground.jpg");
	public static final ImgWrapper whatever   = new ImgWrapper( "/images/whatever.jpg");
	
	
	public BufferedImage get( ImgWrapper iw) {
		return iw.img;
	}
}

Ein Verwender könnte sich dann ein Image besorgen mit
Code:
ImageLibrary.get( ImageLibrary.background);
 

hdi

Top Contributor
Hm mal ne Frage zu der Version mit dem ImgWrapper:

Was müsste ich denn jetzt machen, wenn ich will dass er anfängt alles zu laden?
Ich meine die ganzen Dinge werden doch nur initialisiert, wenn man die Klasse aufruft, oder nicht?
Ich will ja kontrollieren, wann die Bilder geladen werden sollen... Das soll ja nicht zB
beim Programmstart sofort passieren, weil ich das ja eben anzeigen will was er grad lädt, und ich will
auch entscheiden können ob er erst Bilder oder sounds lädt, oder ne Inet-Verbindung aufbaut etc.

Das gleiche gilt auch für die Version mit Hashmap. Wann wird denn dieses "static{}" aufgerufen?
 

Murray

Top Contributor
Der static{}-Block (also der Class-Initializer) wird aufgerufen, bevor zum ersten Mal jemand etwas mit der ImageLib tut. Spätenstens, wenn irgendwo eine Methode der Klasse aufgerufen wird, ist dieser Initializer durchlaufen worden. Das gleiche gilt auch für die Zuweisungen in den Deklarationen der statischen Member.

Wenn Du kontrollieren willst, wann die Bilder geladen werden, dann brauchst Du doch eine eigene init-Methode (die dann natürlich auch aufgerufen werden muss, bevor die Images verwendet werden).

Das könnte dann in etwa so aussehen:

Code:
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;


public class ImageLibrary {
   
   public static class ImgWrapper {
      final BufferedImage img;
      
      private ImgWrapper( final String path) {
         BufferedImage img = null;
         try {
            img = ImageIO.read(ImageLibrary.class.getResourceAsStream( path));
         } catch ( IOException e) {
            e.printStackTrace();
         }
         this.img = img;
      }
   }
   
   public static ImgWrapper background;
   public static ImgWrapper foreground;
   public static ImgWrapper whatever;
   
   
   public synchronized void init() {
      background = new ImgWrapper( "/images/background.jpg");
      foreground = new ImgWrapper( "/images/foreground.jpg");
      whatever   = new ImgWrapper( "/images/whatever.jpg");
   }

   public BufferedImage get( ImgWrapper iw) {
      return iw.img;
   }
}

Jetzt könnte man noch sicherstellen, dass init nur einmal ausgeführt wird, auch wenn der Verwender es mehrfach aufruft:

Code:
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;


public class ImageLibrary {
   
   public static class ImgWrapper {
      final BufferedImage img;
      
      private ImgWrapper( final String path) {
         BufferedImage img = null;
         try {
            img = ImageIO.read(ImageLibrary.class.getResourceAsStream( path));
         } catch ( IOException e) {
            e.printStackTrace();
         }
         this.img = img;
      }
   }
   
   private static boolean initialized;

   public static ImgWrapper background;
   public static ImgWrapper foreground;
   public static ImgWrapper whatever;
   
   
   public synchronized void init() {
      if ( !initialized) {
         initialized = true;
         background = new ImgWrapper( "/images/background.jpg");
         foreground = new ImgWrapper( "/images/foreground.jpg");
         whatever   = new ImgWrapper( "/images/whatever.jpg");
      }
   }

   public BufferedImage get( ImgWrapper iw) {
      return iw.img;
   }
}

Und fool-proof wird es, wenn man die Initialisierung bei Bedarf spätestens dann automatisch macht, wenn das erste Mal ein Image geholt werden soll:

Code:
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;


public class ImageLibrary {
   
   public static class ImgWrapper {
      final BufferedImage img;
      
      private ImgWrapper( final String path) {
         BufferedImage img = null;
         try {
            img = ImageIO.read(ImageLibrary.class.getResourceAsStream( path));
         } catch ( IOException e) {
            e.printStackTrace();
         }
         this.img = img;
      }
   }
   
   private static boolean initialized;

   public static ImgWrapper background;
   public static ImgWrapper foreground;
   public static ImgWrapper whatever;
   
   
   public synchronized void init() {
      if ( !initialized) {
         initialized = true;
         background = new ImgWrapper( "/images/background.jpg");
         foreground = new ImgWrapper( "/images/foreground.jpg");
         whatever   = new ImgWrapper( "/images/whatever.jpg");
      }
   }

   public synchronized BufferedImage get( ImgWrapper iw) {
      init();
      return iw.img;
   }
}
 

Murray

Top Contributor
Der Vollständigkeit halber hier noch die Version mit Annotations (hier wieder mit Class-Initializer; mit einer expliziten init-Methode geht es natürlich ähnlich wie im anderen Beispiel - allerdings kann man mangels get-Methode nicht so einfach die automatische Initialisierung einbauen):
Code:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;


public class ImageLibrary {
	
	//--- Wir definieren unsere eigene Annotation
	@Retention(RetentionPolicy.RUNTIME) //--- die Annotation soll zur Laufzeit im Bytecode verfuegbar sein
	@Target(ElementType.FIELD) //--- die Annotaion bezieht sich auf Variablen (und nicht etwa z.B. auf Methoden)
	@interface Path {
		public String value(); //--- es gibt genau einen Parameter in dieser Annotation
	}

	
	//--- Jetzt folgen die Deklarationen der Member; diese bekommen per Annoation
	//--- den jeweiligen Datenamen "angeklebt"
	
	@Path( "images/background.jpg")
	public static BufferedImage background;
	
	@Path( "images/foreground.jpg")
	public static BufferedImage foreground;

	@Path( "images/whatever.jpg")
	public static BufferedImage whatever;
	
	
	//--- Im Class-Initializer werden jetzt alle mit unserer Annotation ausgezeichneten 
	//--- Member gesucht und initialisiert 
	static {
		Class libCls = ImageLibrary.class;
		for ( Field fld : libCls.getDeclaredFields()) { //--- alle in dieser Klasse deklarierten Felder
			Path pathAnno =	fld.getAnnotation( Path.class);
			if ( pathAnno != null) { //--- ist das Feld entsprechend annotiert?
				try  {
					//--- Wert aus der Annotaion holen
					String imgPath = pathAnno.value();
					
					//--- Image-Objekt erzeugen
					BufferedImage img = ImageIO.read(ImageLibrary.class.getResourceAsStream( imgPath));
					
					//--- gerade erzeugtes Objekt in das statisches Member in dieser Klasse packen
					fld.set( null, img);
				} catch ( Exception e) {
					e.printStackTrace();
				}
			}
		}
 	}	

}
 

hdi

Top Contributor
Ich hab mir die ganze Zeit gedacht "Mensch gäbe es doch ne Funktion, die weiss welche statischen Elemente meine Klasse hat", und so ganz nebenbei machst du in deinem code genau das ;) Dieses class.getDeclaredField() kannte ich nicht...

Dein letztes Code Beispiel ist..nun eigentlich kein Beispiel mehr, sondern eine wie ich finde extrem schöne Umstezung und Lösung zu meinem Problem. Dafür (und auch für alle Bsp davor) möchte ich dir danken, echt immer wieder erstaunlich welche Qualität dieses Forum hat. Es gibt hier soviele Leute die sich echt den Arsch aufreissen um einem zu helfen!

Aber b2t, irgendwie denk ich mir grad, wieso eigentlich so kompliziert (nicht hauen jetzt) Kann ich nicht einfach sagen, meine Library hat nur ein einziges Objekt (privat) :

Code:
private static Map<BufferedImage, String> images;

und überhaupt gar keine expliziten Images. Dann würde ich nur ne Methode machen:

Code:
public static void init(JLabel labelFürDenLadeScreen){
		
		images = new HashMap<BufferedImage,String>();
		List<File> list = alleDateienImOrdner"/images";
		for(File f : images){
			String name = f.getPath;
			try{
                        labelFürDenLadeScreen.setText("Loading "+name);
			BufferedImage img = IO.read(class.getRessourceAsStream(name));
			images.put(img,name);
			} catch(){}
		}
	}

und wenn man dann mal n bild will:

Code:
	public BufferedImage get(String imgName){
		images.get(imgName);
	}

Ich meine dann kann ich jetz Bilder umbenennen, löschen, adden, ohne dass ich dann in der LibraryKlasse anfangen muss, irgendwelche Path Annotatsion etc zu ändern.Er lädt halt ganz einfach alle,
und alles was man wissen muss ist wie die heissen, wenn man sich eins holen will. Dafür öffnet man kurz den Images-Ordner im Projekt und sieht sofort was es so gibt..

Ist das nicht die beste Lösung? Oder geht das nicht, ich denke da an die jar-Integrität.. also was ich meine ist,
ich weiss schon wie ich nen Ordner öffnen kann in Java, aber nicht so recht wie ich den Images-Ordner ansprechen kann innerhalb des Jar-Archivs, sodass es da bei jedem funktioniert.
Das is ja das gleiche wie bei den Images, wenn man das nicht so macht wie oben funktioniert es auch nur bei dem, der den Projektordner hat, aber nicht bei Leuten die nur das fertige jar vor sich liegen haben...

Nochmal nach ner letzten Hilfe würd ich da wünschen
 

Murray

Top Contributor
Natürlich kann man so auch machen - in dem Fall macht die Library dann nur das Caching. Ich würde es aber eher als Nachteil empfinden, das Wissen um die Dateinamen in der Anwendung zu haben; wenn Du eine Datei umbenennst, dann musst Du das an allen Stellen im Code nachziehen, die mit diesen Namen umgehen.
Wenn ich schon so eine ImageLibrary hätte, dann würde ich dort auch logische Namen (oder eben Member) erwarten, über die ich unabhängig vom konkreten Dateinamen auf die Bilder zugreifen kann.
Das mag aber Geschmackssache sein.
 

hdi

Top Contributor
Das stimmt.. der Aufwand eine Annotation oder eine Membervariable zu ändern ist geringer, als es überall sonst im Code zu ändern ^^

Okay also dann nehm ich das doch so wie von dir gepostet.

THX :!:

und nochma kurz edit: kann ich irgendwie überprüfen, von welchem Typ das Field ist?

Weil dann müsste ich nicht für Images und Sounds zwei libraries machen, sondern kann beides
in einem machen, und wenns halt n bild ist mach ich ImageIO.read und wenns n sound ist dann halt
SoundIO oder was es dann halt dafür gibt..

Ich hab jetz bisschen versucht mit field().getType() instanceof BufferedImage etc aber das bringt alles Fehler....

Geht das nicht?
 

hdi

Top Contributor
uuund nochmal ne Frage, wenn es mir erlaubt ist :oops:

Ich dachte mir es gibt doch n besseres Konzept als per

Code:
BufferedImage.class.isAssignableFrom( fld.getType())

herauszufinden, worum es sich handelt. Denn hier hätte ich das Problem, dass es nicht ein Bild "explosion" und auch einen sound mit diesem Namen geben kann, da ja dann zwei Felder den gleichen Namen hätten.

Und diese Einschränkung ist ja nich so toll, das führt nur dazu dass man den Mediafiles komische Namen geben muss...

Deswegen dachte ich, ich mache doch einzelne Libraries für Sounds, Images, Sprites, und mach ne Oberklasse Library:

Code:
public abstract class Library {

	public void init() {
		for (Field field : ImageLib.class.getDeclaredFields()) {
			MediaPath pathAnno = field.getAnnotation(MediaPath.class);
			if (pathAnno != null) {
				String path = pathAnno.value();
				Object media = createMediaFrom(path); // <---- tu das, was die jeweilige Library machen soll
				try {
					field.set(null, media);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}

	protected abstract Object createMediaFrom(String path);
}

und jetzt überschrieben die einzelnen Libraries nur noch die createMediaFrom-methode, je nachdem ob da jetz n bild geladen wird, oder n Sound etc.

(Die Annotation hab ich übrigens in ne eigene Klasse gepackt jetzt, damit ich die nicht in jeder Library einzeln definieren muss)

So, und jetz wär zB die image-library:

Code:
public class ImageLib extends Library {

	/*
	 * Library of images:
	 */
	@MediaPath("images/loading.jpg")
	public static BufferedImage loading;
	@MediaPath("images/background.jpg")
	public static BufferedImage background;
        // ...

	public ImageLib() {
		super.init();
	}


	@Override
	protected Object createMediaFrom(String path) {
		BufferedImage img = null;
		try {
			img = ImageIO.read(ImageLib.class.getResourceAsStream(path));
		} catch (IOException e) {
			e.printStackTrace();
		}
		return img;
	}
}

So, aber da mach ich jetz wohl was falsch und komm mit den Klassen durcheinander, ich bekomme nämlich folgenden Fehler, wenn ich jetz versuch ne neue ImageLib zu machen:

Exception in thread "main" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(Unknown Source)
at media.ImageLib.createMediaFrom(ImageLib.java:30)
at media.Library.init(Library.java:12)
at media.ImageLib.<init>(ImageLib.java:22)
at StartUp.main(StartUp.java:12)

Woran liegt's?
 

Murray

Top Contributor
Aus irgendwelchen Gründen muss
Code:
ImageLib.class.getResourceAsStream(path)
null liefern. Das dürfte aber mit der neuen Aufteilung nicht zu tun haben (solange alles in einem Jar steckt bzw. die Class- und die Resource-Files im gleichen Verzeichnis liegen).
 

hdi

Top Contributor
und genau das haben sie nicht getan :p ich hab nämlich n neues package "media" gemacht wo diese ganzen klassen drinwaren, ohne den image-ordner darein zu schieben. jetz geht's :) thx
 

didjitalist

Bekanntes Mitglied
singleton mit lazy init ist nur in sehr seltenen fällen sinnvoll. ist zwar das standard pattern, aber nicht wirklich sinnvoll, da man damit in nebenläufigkeitsprobleme rennt.
Code:
public class Singleton
{
  private static final Singleton instance = new Singleton();
  // usw.
}

und jetzt die nächste frage: warum singleton? gibts irgendeinen grund, nur eine imagelib zu erzwingen? bilder nur einmal zu laden ist gut, aber das muss man nicht als singleton lösen. bunker irgendwo ne imagelib und gut is.

preloading aller resourcen hat nen gewissen charme. in probleme rennst du aber dann, wenn nicht alle resourcen gleichzeitig in den heap passen. in vielen fällen ist nen simpler cache (LinkedHashMap z.b.) die bessere lösung. häufig benötigte daten liegen sauber im cache, selten benötigte daten fliegen irgendwann raus und belasten den heap nicht. was ich für sowas gern benutze ist nen allgemeiner stream cache, der einfach alle resourcen verwaltet. einfach resourcen immer erstmal vollständig einlesen und in nen ByteArrayInputStream schmeissen. dadurch lässt sich auch exzellent einfach die größe des caches ermitteln und kontrollieren.
 

hdi

Top Contributor
also wenn ich mir deinen text durchlese verstehe ich nur bahnhof. Aber dass du recht hast, weiss ich trotzdem,
weil ich bin sogar in dieses heap problem gelaufen:

ich hab mal zum test grosse bilddateien laden lassen, um mal zu kucken wie lange son preloading überhaupt braucht, aus interesse.

mich würde mal interessieren, wie gross der heap ist? ist das ein fixer wert, oder hängt das vom eigenen pc oder sonst was ab? Soo gross scheint er ja echt nicht zu sein, wenn man schon ne exception bei einem einzigen grösseren bild bekommt...

Wenn ich daran denk dass ich schon einige sounds hab, und auch noch hintergrundmusik, (ganze mp3 lieder sind ja auch paar mb gross) dann denk ich mir schon ich sollte aufpassen dass es den heap nicht sprengt.
 

Murray

Top Contributor
Beim Start der VM kann man angeben, wie groß der Heap sein soll, indem man der VM die Option -Xmx übergibt.

Bsp.: java -Xmx500m name.der.Klasse

Damit darf sich die VM bis zu 500 MB Speicher für den Heap genehmigen.

//edit: Typo
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
S JFrame mit Hintergrundbild und Button Java Basics - Anfänger-Themen 4
K Java JFrame mit Hintergrundbild erstellen Java Basics - Anfänger-Themen 1
Fab1 Buttons auf ein Hintergrundbild(JFrame) setzen Java Basics - Anfänger-Themen 24
H Hintergrundbild auf JFrame Java Basics - Anfänger-Themen 10
C Hintergrundbild im JFrame skalieren Java Basics - Anfänger-Themen 2
W Hintergrundbild im JFrame Java Basics - Anfänger-Themen 4
N Java Spiel Figur auf dem Hintergrundbild bewegen. Java Basics - Anfänger-Themen 11
J Bild auf Hintergrundbild zeichnen Java Basics - Anfänger-Themen 5
Elyt JPanel als HintergrundBild Java Basics - Anfänger-Themen 7
CptK Hintergrundbild Java Basics - Anfänger-Themen 2
P Hintergrundbild in Swing einfügen Java Basics - Anfänger-Themen 3
A Benötige GUI Objekt für Hintergrundbild Java Basics - Anfänger-Themen 3
K Erste Schritte GUI - Hintergrundbild und darauf Buttons Java Basics - Anfänger-Themen 2
D java jbuttons auf dem Hintergrundbild Java Basics - Anfänger-Themen 11
M Hintergrundbild für JButton Java Basics - Anfänger-Themen 6
S Swing, Panel über Hintergrundbild!! Java Basics - Anfänger-Themen 6
J [JAVA] Bild in jar einbinden (Hintergrundbild)? Java Basics - Anfänger-Themen 8
D GUI mit Hintergrundbild Java Basics - Anfänger-Themen 13
Haubitze_Broese Hintergrundbild im JPanel? Java Basics - Anfänger-Themen 2
H Hintergrundbild Java Basics - Anfänger-Themen 8
W Button ausrichten / Hintergrundbild Java Basics - Anfänger-Themen 9
D Hintergrundbild einfügen Java Basics - Anfänger-Themen 4
T Hintergrundbild im JPanel Java Basics - Anfänger-Themen 7
A Problem mit Hintergrundbild in Applet Java Basics - Anfänger-Themen 2
G Hintergrundbild Java Basics - Anfänger-Themen 7
G Hintergrundbild mit sensitiven Bereichen Java Basics - Anfänger-Themen 2
G Hintergrundbild in Frame Java Basics - Anfänger-Themen 15
T Button Hintergrundbild machen ? Java Basics - Anfänger-Themen 19
G Hintergrundbild mit Transparentem Label Java Basics - Anfänger-Themen 5
G Hintergrundbild im jPanel Java Basics - Anfänger-Themen 27
D Windows Hintergrundbild ändern? Java Basics - Anfänger-Themen 5
J Problem mit Hintergrundbild Java Basics - Anfänger-Themen 13
K striche die sich auf dem hintergrundbild bewegen Java Basics - Anfänger-Themen 10
S Problem mit Hintergrundbild Java Basics - Anfänger-Themen 8
D Hintergrundbild nur in der Entwicklungsumgebung sichtbar Java Basics - Anfänger-Themen 8
B JLabel auf Hintergrundbild Java Basics - Anfänger-Themen 9
fragenÜber(fragen); Turtle Grafik mit GUI (JFrame) Java Basics - Anfänger-Themen 3
E JFrame + Buffer-strategy Java Basics - Anfänger-Themen 8
I JFrame / Screen auf zweitem (definiertem) Monitor öffnen Java Basics - Anfänger-Themen 3
luggas89 Mit Jframe live zeichnen Java Basics - Anfänger-Themen 4
C mehrere JPanel in ein JFrame bringen Java Basics - Anfänger-Themen 9
B HSQL mit JFrame steuern Java Basics - Anfänger-Themen 4
D Wie Objekte im JFrame frei bewegen lassen? Java Basics - Anfänger-Themen 3
D Erste Schritte png in JFrame anzeigen? Java Basics - Anfänger-Themen 3
Thomathy Interface Wie schließt man ein anderes JFrame Fenster? Java Basics - Anfänger-Themen 6
D Probleme mit JFrame und der Größe Java Basics - Anfänger-Themen 8
P JFrame, Linien zeichnen, MouseListener Java Basics - Anfänger-Themen 2
S Kontrollieren ob jframe disposed ist Java Basics - Anfänger-Themen 3
Elyt JFrame in den Hintergrund verschieben Java Basics - Anfänger-Themen 3
OSchriever JFrame-Anwendungsfenster verschieben Java Basics - Anfänger-Themen 17
M Bild in JFrame Java Basics - Anfänger-Themen 1
S Klassenaufruf über JFrame Button Java Basics - Anfänger-Themen 3
W 2 JPanel in einem JFrame Java Basics - Anfänger-Themen 4
CptK Interface Klasse Frame (extends JFrame) aus anderer Klasse schließen Java Basics - Anfänger-Themen 7
S JFrame Java Basics - Anfänger-Themen 15
I JFrame proportional verkleinerbar machen Java Basics - Anfänger-Themen 3
B Java JFrame zeichnen Java Basics - Anfänger-Themen 4
ReinerCoder Vererbung von JFrame in einer Klasse entfernen Java Basics - Anfänger-Themen 5
T Auslagern von Methoden bei einem JFrame Java Basics - Anfänger-Themen 6
N Erste Schritte JFrame Caesar-Verschlüsselung Java Basics - Anfänger-Themen 23
B Erste Schritte Objekte von JFrame der Fenstergröße anpassen Java Basics - Anfänger-Themen 3
J JFrame Fenster öffnet sich nicht Java Basics - Anfänger-Themen 7
3 JFrame immer im Hintergrund Java Basics - Anfänger-Themen 1
F Interface JFrame mit if-Abfrage automatisch schließen lassen? Java Basics - Anfänger-Themen 3
R JFrame nicht verschiebbar Java Basics - Anfänger-Themen 2
T Wenn JFrame Textfelder Hintergrund Grün dann... (if) Java Basics - Anfänger-Themen 3
Aruetiise Variablen JFrame und Variablen Java Basics - Anfänger-Themen 3
H Eclipse JFrame Java Basics - Anfänger-Themen 3
C Variablen von einem JFrame in einen anderen übertragen Java Basics - Anfänger-Themen 3
M Bild wird von JFrame nicht geladen Java Basics - Anfänger-Themen 12
I JFrame minimieren wenn anderes Programm minimiert wird Java Basics - Anfänger-Themen 1
K Methoden Methode starten wenn JFrame geöffnet wird Java Basics - Anfänger-Themen 2
D Erste Schritte JFrame Inhalte werden nicht angezeigt Java Basics - Anfänger-Themen 8
A Variablen In anderer Klasse auf Objekte von JFrame zugreifen Java Basics - Anfänger-Themen 1
B Ist MyFrame oder JFrame besser? Java Basics - Anfänger-Themen 3
Y JFrame sichtbarkeit Java Basics - Anfänger-Themen 4
KeVoZ_ Label auf JFrame willkürlich Positionieren Java Basics - Anfänger-Themen 2
Dechasa Interface JFrame mit mehreren Übereinander liegenden JPanel Java Basics - Anfänger-Themen 5
P JFrame nur einmal öffnen Java Basics - Anfänger-Themen 4
D JFrame - 10 Sekunden bis zum schließen warten. Java Basics - Anfänger-Themen 2
V Tastatur initialisieren JFrame Probleme Java Basics - Anfänger-Themen 6
J JPG in JFrame anzeigen lassen Java Basics - Anfänger-Themen 3
J JFrame ausgabe von Werten Java Basics - Anfänger-Themen 9
F GUI als Klasse oder extend JFrame? Java Basics - Anfänger-Themen 6
F JFrame resize verschiebt JPanel Java Basics - Anfänger-Themen 3
S Wieso wird mein JFrame transparent dargestellt? Java Basics - Anfänger-Themen 5
L [JFrame] Exception - woher? Java Basics - Anfänger-Themen 8
thomasbomme Grafikfehler JFrame- Cleartype Java Basics - Anfänger-Themen 1
GreyFox Arbeit mit JFrame Java Basics - Anfänger-Themen 8
T Erste Schritte 2 Codes zusammen fügen / Label in JFrame Java Basics - Anfänger-Themen 1
Z Zwei Images auf einem JFrame - Aber nur eins wird angezeigt! Java Basics - Anfänger-Themen 5
N Input/Output Wenn kein Input, dann Fehler anzeigen lassen im JFrame Java Basics - Anfänger-Themen 6
W 2 JPanels in 2Klasse in einem JFrame zusammenfügen Java Basics - Anfänger-Themen 12
dat_vin JFrame öffnet sich mehrmals Java Basics - Anfänger-Themen 6
M JFrame Bild einfügen Java Basics - Anfänger-Themen 3
M Rahmen für undekorierten JFrame Java Basics - Anfänger-Themen 6
S JPanel wird versetzt auf JFrame gelegt Java Basics - Anfänger-Themen 2
B Erste Schritte JFrame in Klasse auslagern Java Basics - Anfänger-Themen 4
H JFrame komplett schließen Java Basics - Anfänger-Themen 3
S Brauche hilfe bei Pong (JFrame) Java Basics - Anfänger-Themen 2

Ähnliche Java Themen


Oben