getSize() - Echte Höhe bestimmen

Hallöle,

leider noch nicht.
Also ich habe das als Quellenordner im src Ordner und den Pfad so geschrieben.
Eclipse gibt mir dann diese URL an und das Bild wird auch angezeigt:
file:/Users/Lukas/Documents/Schule/Informatik/Seminarkurs/CafeInternationalGrafik/cafeint/bin/demo_DE2.jpg

Wenn ich dann eine jar ausführe, sind sie trotzdem wieder weg.
Ich hab die JAR mal entpackt um zu gucken, was drin ist.
Gleich im obersten Verzeichnis sind alle Bilder aus diesem Ordner. Außerdem ist dort ein Unterordner “spiel” und darin sind dann die Klassendateien.
spiel ist in dem Fall das Package, wo die ganzen Klassen drin sind.

Gruß
Lukas

Oh je… jetzt habe ich doch glatt “getCodeBase()” mit “getJarBase()” verwechselt. Das bedeutet, mit “getCodeBase()” kommst du in das Jar und mit “getJarBase()” in das Verzeichnis in welchem sich das Jar befindet. Letzteres wäre also die Methode für deine ursprüngliche Verzeichniskonstellation. Dabei muss aber der “resource”-Ordner neben dem Jar stets mitkopiert werden.

Hallöle,

vielen Lieben Dank!
Jetzt funktioniert es. Und zwar in beiden Variationen. Also in Eclipse und in der JAR-Datei.
Aber was soll das mit dem Mitkopieren des Ordners? Klappt auch so. :slight_smile: Oder hab ich was falsch bzw. dann wohl richtig gemacht? :smiley:

Ich habs nun so erledigt:

				URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE2.jpg");
				Icon icon = new ImageIcon(url);
				Spielfeld.spielfeldlabeltisch.get(n).setIcon(icon);
			} catch(MalformedURLException e) {
				// da passiert noch irgendwas später	
			}```


Ich werde ich demnächst aber noch mit der Bildgröße beschäftigen müssen. Es ist für mein Projekt ein Unding, dass das JLabel die Teile nicht skaliert. Zumal das ja dann beim verändern der Größe des JFrames nicht mitwächst/schrumpft.
Da muss ich noch eine Lösung finden, dass das 100% auf das Label kommt. Macht man wahrscheinlich mit BufferedImage. Ich lese mich da mal ein. Also die Tage.

Vielen Dank für Eure Hilfe!

Gruß
Lukas

Wenn du “getJarBase()” verwendest, gehört der Ordner “resources” in das Verzeichnis, in welchem sich deine Jar befindet. Wenn du “getCodeBase()” verwendest, gehört der Ordner “resources” mit in die Jar, also in Eclipse in den src-Ordner, von wo aus es mit in die Jar exportiert wird.

Für dein Skalierungsproblem solltest du es statt mit JLabel und ImageIcon mit einer JComponent und einem BufferedImage ausprobieren. Durch Überschreiben der “paintComponent()”-Methode kannst du das BI per “.drawImage(bi, 0,0, getWidth(), getHeight())” auf die ganze Fläche der JComponent skalieren.

Hallöle,

bei mir ist das andersherum. Ich nutze getJar und habe den Ordner direkt in der Jar drin. Ansonsten existiert parallel im Verzeichnis der Jar der Ordner nicht nochmal.
Aber falls das jetzt nur Zufall ist und beim nächsten mal wieder nicht arbeitet, nehme ich das in den Hinterkopf, danke schön.

Das ist leider genau das, was ich verhindern wollte. Mein ganzes Konstrukt basiert auf Labels die ich da eingefügt habe. Meine GUI-Kenntnisse sind so Notdürftig, ich kann mich nicht auch noch mit paintComponents umherärgern.

Ich werde erstmal versuchen, ob ich es schaffe skalierte Bilder mit JLabel zu kombinieren. :wink:
Wenn nicht, komme ich darauf zurück.

Vielen Lieben Dank
Lukas

[QUOTE=FranzFerdinand]bei mir ist das andersherum. Ich nutze getJar und habe den Ordner direkt in der Jar drin. Ansonsten existiert parallel im Verzeichnis der Jar der Ordner nicht nochmal.
Aber falls das jetzt nur Zufall ist und beim nächsten mal wieder nicht arbeitet, nehme ich das in den Hinterkopf, danke schön.[/QUOTE]Nee, warte mal… nu verwirrst du mich aber. dein Programmstück in Post #77 hatte dann ja funktionieren müssen, ohne dass du den “resource”-Ordner ins bin- oder src-Verzeichnis verschiebst. Ich hatte das dann also von Anfang an doch nicht verwechselt. Was aber noch sein kann, ist dass meine Utility-Klasse auf das Eclipse-bin-Verzeichnis gar keine Rücksicht nimmt und diese Klasse in Eclipse deswegen gar nicht korrekt funktioniert.

Liegen die Bilder vielleicht sowohl im Jar als auch außerhalb nach den vielen Versuchen? Das klingt alles etwas durcheinander und unsauber.

Die Idee: Lad die bilder auf imgur

Hallöle,

ähm es hat etwas länger gedauert mit der Bearbeitung. Ich habe nun ein paar Wochen selbst daran gearbeitet, viel umhergefummelt und bin leider nicht einen Schritt weiter gekommen. Aber ich glaube, es ist im aktuellen Zustand irgendwie besser als vorher… Also die Voraussetzung meine ich. Aus der ich etwas machen kann.

Ich habe mich nun von diesem lästigen JLabelZeuchs losgesagt und versuche es nun mit folgender Idee:
Ich habe ein GridBagLayout, wie es bereits in den Post von vorher existierte. Und dazu passend generiere ich nun anstatt JLabels entsprechende JPanel, die mit der paint Graphics Methode, die mir ans Herz gelegt wurde arbeitet.

Die Idee ist folgende:
Ich habe die Klasse Spielzelle mit folgendem Inhalt:


import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Spielzelle extends JPanel {
	
	private int zellart; //0=Nichts;1=Stuhl;2=Tisch
	private BufferedImage tischimg;

	public Spielzelle(int zellart) {
		this.zellart = zellart;
		this.addMouseListener(new MouseAdapter() {
		      public void mouseClicked(MouseEvent evt) {
		    	  klick();
		      }
		});
	}
	
	public int getZellart() {
		return zellart;
	}

	public void setZellart(int zellart) {
		this.zellart = zellart;
	}
	
	public void paintComponent(Graphics stift) {
		super.paintComponent(stift);
		int height = getHeight();
        int width = getWidth();
        /*try {
        	URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE2.jpg");
            this.tischimg = ImageIO.read(this.getClass().getResourceAsStream("/background.jpg"));
        } catch (IOException e) { }
        
        stift.drawImage(this.tischimg, 0, 0, width, height, null);*/
	}
	
	public void klick() {
		this.repaint();
	}
	
}```

Das bezeichnet diese 11 mal 11 Zellen da in der Mitte. Diese hab ich dann in drei Arten eingeteilt, die in einem int dargestellt werden. 0 ist einfach ein Nichts, eine leere Zelle, die nur da ist, damit das Design nicht zerstört wird. Platzhalter. 1 sind die Stühle und 2 sind die Tische.

Standardmäßig wird alles mit 0 erstellt und später wenn ich Tische und Stühle definiere wird das umgeschrieben.


Meine Spielfeldmethode sieht weiterhin wenig verändert aus:
```package spiel;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JLabel;
import javax.swing.JPanel;

class Spielfeld extends JPanel {

	protected static Spielzelle spielfeldlabel[][] = new Spielzelle[11][11];
	protected static ArrayList<Spielzelle> spielfeldlabeltisch = new ArrayList<Spielzelle>(12);
	protected static ArrayList<Spielzelle> spielfeldlabelstuhl = new ArrayList<Spielzelle>(24);
	protected static int stuhlnummer;
	protected static int tischnummer;
	
	public Spielfeld() {
		setLayout(new GridLayout(11,11));
		for(int i=0;i<11;i++) {
			for(int n=0;n<11;n++) {
				spielfeldlabel[n]** = new Spielzelle(0);
				spielfeldlabel[n]**.setBackground(new Color(255,255,255));
				spielfeldlabel[n]**.setOpaque(true);
				add(spielfeldlabel[n]**);
			}
		}
		feldmalen();
	}
	
	public void feldmalen() {
		spielfeldlabeltisch.add(spielfeldlabel[4][3]);
		spielfeldlabeltisch.add(spielfeldlabel[5][2]);
		spielfeldlabeltisch.add(spielfeldlabel[6][3]);
		spielfeldlabeltisch.add(spielfeldlabel[7][4]);
		spielfeldlabeltisch.add(spielfeldlabel[8][5]);
		spielfeldlabeltisch.add(spielfeldlabel[7][6]);
		spielfeldlabeltisch.add(spielfeldlabel[6][7]);
		spielfeldlabeltisch.add(spielfeldlabel[5][8]);
		spielfeldlabeltisch.add(spielfeldlabel[4][7]);
		spielfeldlabeltisch.add(spielfeldlabel[3][6]);
		spielfeldlabeltisch.add(spielfeldlabel[2][5]);
		spielfeldlabeltisch.add(spielfeldlabel[3][4]);
		
		spielfeldlabelstuhl.add(spielfeldlabel[4][4]);
		spielfeldlabelstuhl.add(spielfeldlabel[5][1]);
		spielfeldlabelstuhl.add(spielfeldlabel[6][2]);
		spielfeldlabelstuhl.add(spielfeldlabel[7][3]);
		spielfeldlabelstuhl.add(spielfeldlabel[8][4]);
		spielfeldlabelstuhl.add(spielfeldlabel[7][5]);
		spielfeldlabelstuhl.add(spielfeldlabel[6][6]);
		spielfeldlabelstuhl.add(spielfeldlabel[5][7]);
		spielfeldlabelstuhl.add(spielfeldlabel[4][6]);
		spielfeldlabelstuhl.add(spielfeldlabel[3][5]);
		spielfeldlabelstuhl.add(spielfeldlabel[2][4]);
		spielfeldlabelstuhl.add(spielfeldlabel[3][3]);
		spielfeldlabelstuhl.add(spielfeldlabel[4][2]);
		spielfeldlabelstuhl.add(spielfeldlabel[5][3]);
		spielfeldlabelstuhl.add(spielfeldlabel[6][4]);
		spielfeldlabelstuhl.add(spielfeldlabel[9][5]);
		spielfeldlabelstuhl.add(spielfeldlabel[8][6]);
		spielfeldlabelstuhl.add(spielfeldlabel[7][7]);
		spielfeldlabelstuhl.add(spielfeldlabel[6][8]);
		spielfeldlabelstuhl.add(spielfeldlabel[5][9]);
		spielfeldlabelstuhl.add(spielfeldlabel[4][8]);
		spielfeldlabelstuhl.add(spielfeldlabel[3][7]);
		spielfeldlabelstuhl.add(spielfeldlabel[2][6]);
		spielfeldlabelstuhl.add(spielfeldlabel[1][5]);
		
		
		for(Spielzelle a:spielfeldlabeltisch) {
            a.setBackground(Color.ORANGE);
            a.setZellart(2);
            //final int tischindex = spielfeldlabeltisch.indexOf(a);
            /*a.addMouseListener(new MouseAdapter() {
            	@Override
            	public void mouseClicked(MouseEvent e) {
            		System.out.println("Tisch: "+tischindex);
            		stuhlnummer = tischindex;
            	}
            });*/
        }
        for(Spielzelle b:spielfeldlabelstuhl) {
            b.setBackground(Color.RED);
            b.setZellart(1);
            //final int stuhlindex = spielfeldlabelstuhl.indexOf(b);
            /*b.addMouseListener(new MouseAdapter() {
            	@Override
            	public void mouseClicked(MouseEvent e) {
            		System.out.println("Stuhl: "+stuhlindex);
            		tischnummer = stuhlindex;
            	}
            });*/
        }
   
	}
	
}

class Kartenstapel extends JPanel {
	public Kartenstapel() {
		setLayout(new GridLayout(5,2));
		Random rand = new Random();
		for(int i=0;i<10;i++) {
			JLabel label = new JLabel();
		    label.setBackground(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
		    label.setOpaque(true);
		    add(label);
		}
	}
}
 
class AufbauHilfe {
    public static GridBagConstraints createGridBagConstraints(int x, int y, int width, int height, int weightX, int weightY) {
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.gridx = x;
        constraints.gridy = y;
        constraints.gridwidth = width;
        constraints.gridheight = height;
        constraints.weightx = weightX;
        constraints.weighty = weightY;
 
        return constraints;
    }
 
    public static JLabel createRandomBackgroundLabel(String text) {
        Random rand = new Random();
        JLabel label = new JLabel(text);
        label.setBackground(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
        label.setOpaque(true);
 
        return label;
    }
}```

Habe lediglich aus JLabels JPanel gemacht.

Es werden daraus folglich die folgenden Layouts erstellt:
```Container contentPane = spielframe.getContentPane();
        contentPane.setLayout(gridlayout);
        //======
        spielframe.add(AufbauHilfe.createRandomBackgroundLabel("LINKSOBEN"), AufbauHilfe.createGridBagConstraints(0, 0, 1, 1, 1, 1));
        spielframe.add(AufbauHilfe.createRandomBackgroundLabel("LINKSUNTEN"), AufbauHilfe.createGridBagConstraints(0, 1, 1, 1, 1, 1));
        Kartenstapel kartenstapel = new Kartenstapel();
        spielframe.add(kartenstapel, AufbauHilfe.createGridBagConstraints(2, 0, 1, 1, 1, 1));
        //spielframe.add(AufbauHilfe.createRandomBackgroundLabel("RECHTSOBEN"), AufbauHilfe.createGridBagConstraints(2, 0, 1, 1, 1, 1));
        spielframe.add(AufbauHilfe.createRandomBackgroundLabel("RECHTSUNTEN"), AufbauHilfe.createGridBagConstraints(2, 1, 1, 1, 1, 1));
 
        Spielfeld spielpanel = new Spielfeld();
        spielframe.add(spielpanel, AufbauHilfe.createGridBagConstraints(1, 0, 1, 2, 3, 3));
         
        spielframe.pack();
        spielframe.setLocationRelativeTo(null);```

Hat sich auch nicht verändert zum letzten mal. ;)


Nun stehe ich aber wieder vor dem gleichen Problem, woran ich ohne jeglichen Fortschritt seit November hantiere.
Wie male ich da jetzt Bilder rauf?

Also ich habe in der Klasse Spielzelle meine Paintmethode, mit der ich arbeiten möchte.
Ich möchte nun, ganz primitiv eigentlich, dass er via BufferedImage ein Bild lädt und in die Größe zurechtschneidet, die das JPanel selbst hat und es 1:1 auf 100% Zellgröße da rauf kleistert.

Kann mir das nochmal jemand erklären?

Wenn ich weiß, wie ich ein einziges Bild lade, dann kann ich auch den Rest dazu machen. Dann lädt er auch, abhängig von der Zellart (Tisch oder Stuhl) seine Bilder. Etc. etc.

Ich bitte noch einmal um Erklärung!

Vielen Dank!
Liebe Grüße
Lukas ;)

Also das BufferedImage kannst (besser gesagt solltest) du in der Klasse des jeweiligen JPanels speichern, also etwa den JPanel mit diesem BI als Parameter instanzieren. Alles in Allem sähe eine Klasse ImagePanel dann so aus:

  private final BufferedImage image;

  public ImagePanel(BufferedImage image) {
    this.image = image;
  }

  protected void paintComponent(Graphics g) {
    super.paintComponent();
    int w = getWidth();
    int h = getHeight();
    g.drawImage(image, 0, 0, w, h, null);
  }
}```
oder Analog zu deiner Spielzelle:
```public class Spielzelle extends JPanel {
  private static final BufferedImage[] IMAGES;

  static {
    IMAGES = loadImages();

  private int zellart;


  public Spielzelle(int zellart) {
    setZellart(zellart);
  }

  protected void paintComponent(Graphics g) {
    super.paintComponent();
    int w = getWidth();
    int h = getHeight();
    g.drawImage(IMAGES[zellart], 0, 0, w, h, null);
  }

  public int getZellart() {
    return zellart;
  }

  public void setZellart(int zellart) {
    if(zellart < 0 || zellart > IMAGES.length) {
      throw new IllegalArgumentException("ungültige zellart " + zellart);
    }
  }

  private static BufferedImage[] loadImages() {
    //... Do it yourself ;)
  }
}```

Hallo und Danke, dass Du Dir Zeit genommen hast,

ich muss aber gestehen, das hab ich jetzt schon länger nicht mehr gehabt: Ich verstehe nichts. Gar nichts. Angefangen mit dem static, was Du da drum herum machst, weiter mit der Tatsache, dass IMAGES so in Kapitälchen steht, und und und.

Ich habe es mal versucht bei mir einzubauen in meine Klasse.

Zur Erinnerung: So sah die Klasse Spielzelle einmal aus:

 
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
 
import javax.imageio.ImageIO;
import javax.swing.JPanel;
 
public class Spielzelle extends JPanel {
   
    private int zellart; //0=Nichts;1=Stuhl;2=Tisch
    private BufferedImage tischimg;
 
    public Spielzelle(int zellart) {
        this.zellart = zellart;
        this.addMouseListener(new MouseAdapter() {
              public void mouseClicked(MouseEvent evt) {
                  klick();
              }
        });
    }
   
    public int getZellart() {
        return zellart;
    }
 
    public void setZellart(int zellart) {
        this.zellart = zellart;
    }
   
    public void paintComponent(Graphics stift) {
        super.paintComponent(stift);
        int height = getHeight();
        int width = getWidth();
        /*try {
            URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE2.jpg");
            this.tischimg = ImageIO.read(this.getClass().getResourceAsStream("/background.jpg"));
        } catch (IOException e) { }
       
        stift.drawImage(this.tischimg, 0, 0, width, height, null);*/
    }
   
    public void klick() {
        this.repaint();
    }
   
}```

So sieht das jetzt aus, wenn ich versuche da irgendwie irgendetwas zu machen:

```package spiel;

import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Spielzelle extends JPanel {
	private static final BufferedImage[] IMAGES;
	
	static {
		IMAGES = loadImages();

		private int zellart;

		public Spielzelle(int zellart) {
			this.zellart = zellart;
			this.addMouseListener(new MouseAdapter() {
			      public void mouseClicked(MouseEvent evt) {
			    	  klick();
			      }
			});
		}
	 
	  protected void paintComponent(Graphics g) {
	    super.paintComponent();
	    int w = getWidth();
	    int h = getHeight();
	    g.drawImage(IMAGES[zellart], 0, 0, w, h, null);
	  }
	 
	  public int getZellart() {
	    return zellart;
	  }
	 
	  public void setZellart(int zellart) {
	    if(zellart < 0 || zellart > IMAGES.length) {
	      throw new IllegalArgumentException("ungültige zellart " + zellart);
	    }
	  }
	 
	  private static BufferedImage[] loadImages() {
	    //... Do it yourself ;)
	  }
	}
}```

Es wäre nun einfacher Dir aufzuzählen, in welcher Zeile es keine Fehlermeldungen gibt.

Beispiele:
`{`, `}`, `//... Do it yourself ;)`

Ich verstehe ehrlich gesagt nicht, wo Du das static hernimmst und was das bedeuten möge?
Dadurch verliert ja auch mein gesamter anderer Code an Bedeutung, genau weil ja dann sowas wie `this` gar nicht mehr arbeitet.

Kannst Du das bitte noch einmal erklären? :)

Gruß
Lukas

[QUOTE=FranzFerdinand]Kannst Du das bitte noch einmal erklären? :)[/QUOTE]Öhm ja… kann ich.
Da fehlt 'ne schließende Klammer bei der static-Methode:

        IMAGES = loadImages();
    }```
Die Klammer, die du unter "loadImages()" eingefügt hast, wird dann natürlich wieder überflüssig.
In der "loadImages()"-Methode lädst du alle Images einmal beim Initialisieren der Klasse und gibst sie in einem Array zurück. Im lfd. Programm muss dies dann nicht mehr andauernd bei einem Repaint geschehen. Das Array IMAGES ist deswegen als Klassen-Konstante implementiert und sowas kennzeiche ich mit Capitals.

Hallöle und vielen Dank nochmal für die Erklärung! :slight_smile:

Meine Verwirrung ging tatsächlich nur von dieser einen Klammer aus.
Ich hatte verwundert gedacht, dass das aufgrund der Fehlenden Klammer da ein kompletter Block bis unten hin ist. Aber dass die direkt hinter der Methode fehlt. Peinlich, dass ich das nicht sehe. :smiley:
Aber okay. Nun gut. Es klappt nun erstmal, ohne Fehlermeldung.

So sieht es erstmal aus:


import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;


public class Spielzelle extends JPanel {
	
    private static final BufferedImage[] IMAGES;
    private int zellart;
   
    static {
        IMAGES = loadImages();
    }
    
    public Spielzelle(int zellart) {
    	this.zellart = zellart;
    	this.addMouseListener(new MouseAdapter() {
    		public void mouseClicked(MouseEvent evt) {
    			klick();
            }
        });
    }
     
    protected void paintComponent(Graphics g) {
    	super.paintComponent(g);
        int height = getWidth();
        int width = getHeight();
        g.drawImage(IMAGES[zellart], 0, 0, height, width, null);
    }
     
    public int getZellart() {
    	return zellart;
    }
     
    public void setZellart(int zellart) {
    	this.zellart = zellart;
    }
     
    private static BufferedImage[] loadImages() {
		return null;
    }
    
    public void klick() {
		this.repaint();
	}
    
}```

So und nun muss ich nochmal was zur Theorie mit dem BufferedImageArray fragen.

Also, das funktioniert folgendermaßen. Die Zellart ist 0, 1 oder 2, klar, das sagte ich ja schon mal.
Aber je nachdem, ob die Zellart nun 1 oder 2 ist, ergeben sich daraus wieder eine Menge Bilder.
Um genau zu sein 24 Stühle (Zellart 1) und 12 Tische (Zellart 2).
Diese habe ich bisher über diese Funktion eingelesen, die ich ein paar viele Beiträge vor einem Monat weiter oben durchdiskutiert hatte:
```try {
            URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE2.jpg");
            this.tischimg = ImageIO.read(this.getClass().getResourceAsStream("/background.jpg"));
        } catch (IOException e) { }```

Kann man mir das noch einmal erläutern?
Jetzt wenn alles static ist, funktioniert this ja auch nicht mehr, wie es sollte... :(

Und ähm, meine Hauptklasse gibt übrigens immer einen String zurück, welches Bild dran ist. Also das sind ja Länder.
Wie man hier an dem Beispiel gesehen hat:
```"demo_DE2.jpg"```

Das ist dann so nach dem Motto:
```"demo_"+land+".jpg"```
In wie fern ist das jetzt kompatibel mit meinem Array, den ich da erstellt habe?
DAs muss ich mir jetzt irgendwie noch einmal genauer ansehen.

Aber erstmal muss ich wissen, wie ich die URL wieder richtig einlesen kann.

Schöne Grüße
Lukas

Dann mach halt ein 2D-Array ([][]) draus und dann:

  BufferedImage[][] rc = new BufferedImage[3][];
  rc[0] = new BufferedImage[0];
  rc[1] = new BufferedImage[24];
  rc[2] = new BufferedImage[12];
  for(int n = 0; n < 24; n++) {
    // rc[1][n] = Bild laden
  }
  for(int n = 0; n < 12; n++) {
    // rc[2][n] = Bild laden
  }
  return rc;
}```
Jetzt kannst du noch zwei String-Arrays als Klassenkonstanten erstellen, die die Bildnamen-Teile beinhalten und diese auf "n" in den Schleifen mappen. Ferner musst du zusätzlich noch eine weitere Objektvariable anlegen, mit welcher du die zweite Dimension im IMAGES-Array selektierst, also so etwas wie zellenart. Die drawImage-Methode in paintComponent ändert sich dann wie folgt:
```g.drawImage(IMAGES[zellart][myVar], 0, 0, height, width, null);```

Da sich nur der Dateiname und nicht der Pfad der URL ändert, kannst du diese mit
```URL url = new URL(url, newFilename):```ändern.

Hallöle Hallöle und nochmals vielen Lieben Dank für Deine Antwort,

ich bin dabei das umzusetzen. Aber vielleicht brauche ich dabei nochmal ein klein wenig Hilfe.

Vorerst muss ich sagen, ich hatte einen kleinen Denkfehler.

In der Klasse Gastkarte habe ich nochmal diese zwei Enums:

	   public static enum Land {DE, FR, GB, US, TR, IN, CN, RU, ES, CU, CF, IT, JOKER};```

Das sind 13 Länder und 2 Geschlechter.
Ich hatte etwas falsch gemacht. Ja es sind 12 Tische und 24 verschiedene Stühle. Aber wir wollen ja die Bilder laden.
Und davon ist die Anzahl de facto etwas anders:
Die Tische bekommen ein Land zugeteilt. Also eines von 13 Stück.
Und die Stühle bekommen ein Land und ein Geschlecht zugeteilt. Ergo, kann man sogar von einem 3D Array ausgehen.


Ich habe das aktuell nun in diesem Zustand:
```package spiel;

import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;


public class Spielzelle extends JPanel {
	
    private static final BufferedImage[][][] IMAGES;
    private int zellart; //0=Nichts;1=Stuhl;2=Tisch
    private int irgendwas;
    private int irgendwas2;
   
    static {
        IMAGES = loadImages();
    }
    
    public Spielzelle(int zellart) {
    	this.zellart = zellart;
    	this.addMouseListener(new MouseAdapter() {
    		public void mouseClicked(MouseEvent evt) {
    			klick();
            }
        });
    }
     
    protected void paintComponent(Graphics g) {
    	super.paintComponent(g);
        int height = getWidth();
        int width = getHeight();
        g.drawImage(IMAGES[zellart][irgendwas][irgendwas2], 0, 0, height, width, null);
    }
     
    public int getZellart() {
    	return zellart;
    }
     
    public void setZellart(int zellart) {
    	this.zellart = zellart;
    }
     
    private static BufferedImage[][][] loadImages() {
    	BufferedImage[][][] rc = new BufferedImage[3][][];
    	rc[0] = new BufferedImage[0][0];
    	rc[1] = new BufferedImage[13][2];
    	rc[2] = new BufferedImage[12][0];
    	for(int l=0;l<13;l++) {
    		for(int g=0;g<2;g++) {
    			//Gastkarte.Land.get(l) & Gastkarte.Geschlecht.get(g) ??????
    			/*try {
    	            URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE2.jpg");
    	            //IMAGES[1][1][1] = ImageIO.read(Spielzelle.getClass().getResourceAsStream("/background.jpg"));
    	        } catch (IOException e) { }*/
    		}
    	}
    	for(int l=0;l<12;l++) {
    		//
    	}
    	return rc;
    }
    
    public void klick() {
		this.repaint();
	}
    
}```

Ich bin immer noch in der BufferedImageKlasse und stecke ein wenig fest.

Also man sieht erst einmal, wie ich das versucht habe:
```private static BufferedImage[][][] loadImages() {
    	BufferedImage[][][] rc = new BufferedImage[3][][];
    	rc[0] = new BufferedImage[0][0];
    	rc[1] = new BufferedImage[13][2];
    	rc[2] = new BufferedImage[13][0];
    	for(int l=0;l<13;l++) {
    		for(int g=0;g<2;g++) {
    			//Gastkarte.Land.get(l) & Gastkarte.Geschlecht.get(g) ??????
    			/*try {
    	            URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE2.jpg");
    	            //IMAGES[1][l][g] = ImageIO.read(Spielzelle.getClass().getResourceAsStream("/background.jpg"));
    	        } catch (IOException e) { }*/
    		}
    	}
    	for(int l=0;l<13;l++) {
    		//
    	}
    	return rc;
    }```

0 liegt einfach bei 0,0,0, das ist eben der leere Zustand.
Bei [1] habe ich das ganze auf 13/2 gestellt, wegen 13 Ländern und 2 Geschlechtern. Und das dritte sind die 13 Länder ohne Geschlecht. Ich hoffe man versteht das. ;)
Also habe ich wieder meine Zählschleifen. Habe einfach mal int l für Land und int g für Geschlecht genommen.

Nun bin ich aber immer noch nicht weiter gekommen beim Einlesen der Bilder. Totaler Blackout.
Ich stehe vor folgenden Problemen:
- Ich kann den Enum nicht durchschalten.
Die Dateien heißen ja einfach so: `stuhl_DE_Mann.jpg`, `stuhl_GB_Frau.jpg`, `stuhl_CF_Frau.jpg` bzw. `tisch_FR.jpg`. Prinzip ist sicherlich einfach. ;)

Das heißt die Einlesemethode müsste, wenn Java die entsprechende Methode hätte beispielsweise so heißen:
```URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "stuhl_"+Gastkarte.Land.get(l)+"_"+Gastkarte.Geschlecht.get(g)+.jpg");```

Hoffe ich habe das verständlich und logisch erklärt, wie ich das meine. ;) Aber das durchzuschalten, dazu bin ich irgendwie nicht in der Lage. Enum hat doch auch nicht die Funktion dafür, wie ne ArrayList zum Beispiel, oder?

- Die Zeile dahinter mit dem Bild. Wie lese ich dann noch das Bild aus der URL darüber ein? :)


Das sollte es dann gewesen sein!

Schönes Wochenende euch allen!

Gruß
Lukas

Wenn ich ehrlich bin, wollte ich schon sagen, dass Enums eine viel bessere Lösung sind… Also mal ganz was anderes:

  public static enum Geschlecht {Mann, Frau};
  public static enum Land {DE, FR, GB, US, TR, IN, CN, RU, ES, CU, CF, IT, JOKER};
  public static enum Typ {Stuhl, Tisch};

  private Land l;
  private Geschlecht g;
  private Typ t;
  private BufferedImage i;

  public Spielzelle() {
    this(null, null, null);
  }

  public Spielzelle(Geschlecht g, Land l, Typ t) {
    setLand(l);
    setGeschlecht(g);
    setGeschlecht(t);
  }

  public Geschlecht getGeschlecht() {
    return g;
  }

  public Land getLand() {
    return l;
  }

  public Typ getTyp() {
    return t;
  }

  public void setGeschlecht(Geschlecht g) {
    if(g != this.g) {
      i = null;
    }
    this.g = g;
  }

  public void setLand(Land l) {
    if(l != this.l) {
      i = null;
    }
    this.l = l;
  }

  public void setTyp(Typ t) {
    if(t != this.t) {
      i = null;
    }
    this.t = t;
  }

  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if(i == null && l != null && g != null && t != null) {
      try {
        URL url = new URL(getJarBase(Spielfeld.class), t.toString() + "_" + l.toString() + "_" + g.toString() + ".jpg");
        i = ImageIO.read(url);
      } catch(MalformedURLException e) {
        // react as you like
      } catch(IOExeption e) {
        // react as you like
      }
    }
    if(i != null) {
      g.drawImage(i, 0,0, getWidth(), getHeight(), null);
    }
  }
}```

Hallöle und nochmals Danke für Deine Antwort,

eine sehr interessante Herangehensweise, wie ich finde irgendwie schon eine bessere Variante als vorher. Da hab ich schon ein wenig Probleme gehabt beim durchsehen.

Wie dem auch sei: Ich habe Deine Idee etwas weiterverfolgt:
Meine Klasse Spielzelle sieht so aus:


import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Spielzelle extends JPanel {
	
	public static enum Geschlecht {Mann, Frau};
	public static enum Land {DE, FR, GB, US, TR, IN, CN, RU, ES, CU, CF, IT, JOKER};
	public static enum Typ {Stuhl, Tisch};

	private Land l;
	private Geschlecht g;
	private Typ t;
	private BufferedImage i;
	 
	public Spielzelle() {
		this(null, null, null);
	}
	 
	public Spielzelle(Geschlecht g, Land l, Typ t) {
		setLand(l);
	    setGeschlecht(g);
	    setTyp(t);
	}
	 
	public Geschlecht getGeschlecht() {
		return g;
	}
	 
	public Land getLand() {
	    return l;
	}
	 
	public Typ getTyp() {
	    return t;
	}
	 
	public void setGeschlecht(Geschlecht g) {
		if(g != this.g) {
			i = null;
	    }
	    this.g = g;
	}
	 
	public void setLand(Land l) {
		if(l != this.l) {
			i = null;
	    }
	    this.l = l;
	}
	 
	public void setTyp(Typ t) {
	    if(t != this.t) {
	    	i = null;
	    }
	    this.t = t;
	}
	 
	protected void paintComponent(Graphics gr) {
	    super.paintComponent(gr);
	    if(i == null && l != null && g != null && t != null) {
	    	try {
	    		//URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_DE.jpg");
	    		//URL url = new URL(BaseURL.getJarBase(Spielfeld.class), t.toString() + "_" + l.toString() + "_" + g.toString() + ".jpg");
	    		URL url = null;
	    		if(t.equals(Typ.Stuhl)) {
	    			url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_"+l.toString()+".jpg");
	    			System.out.println(l.toString());
	    		} else if(t.equals(Typ.Tisch)) {
	    			url = new URL(BaseURL.getJarBase(Spielfeld.class), "demo_"+l.toString()+".jpg");
	    		}
	    		System.out.println(url);
	    		i = ImageIO.read(url);
	    	}catch(MalformedURLException e) {
	    	}catch(IOException e) { }
	    }
	    if(i != null) {
	    	gr.drawImage(i,0,0, getWidth(), getHeight(), null);
	    }
	}
}```

Habe einmal in die Klasse mit der paintComponent noch die entsprechende if-Anweisung zum Einlesen gepackt.
Je nachdem, ob der Typ einem Stuhl oder einem Tisch entspricht.
Meine Bilder selbst, muss ich gestehen, habe ich noch nicht gephotoshopt. :) Das vorhin war nur Theorie, wie es werden sollte.
Aktuell behelfe ich mir daher erstmal mit meinem DemoBeispielen. Deshalb steht da `"demo_"+l.toString()+".jpg"`. Das entspricht beispielsweise diesem `"demo_DE.jpg"`, wie es immer in meinen Beispielen steht. ;)

So so und nun hab ich noch die Klasse, wo die Felder alle generiert werden:
```package spiel;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JLabel;
import javax.swing.JPanel;

class Spielfeld extends JPanel {

	protected static Spielzelle spielfeldzelle[][] = new Spielzelle[11][11];
	protected static ArrayList<Spielzelle> spielfeldtisch = new ArrayList<Spielzelle>(12);
	protected static ArrayList<Spielzelle> spielfeldstuhl = new ArrayList<Spielzelle>(24);
	protected static int stuhlnummer;
	protected static int tischnummer;
	
	public Spielfeld() {
		setLayout(new GridLayout(11,11));
		for(int i=0;i<11;i++) {
			for(int n=0;n<11;n++) {
				spielfeldzelle[n]** = new Spielzelle();
				spielfeldzelle[n]**.setBackground(new Color(255,255,255));
				spielfeldzelle[n]**.setOpaque(true);
				add(spielfeldzelle[n]**);
			}
		}
		feldmalen();
	}
	
	public void feldmalen() {
		spielfeldtisch.add(spielfeldzelle[4][3]);
		spielfeldtisch.add(spielfeldzelle[5][2]);
		spielfeldtisch.add(spielfeldzelle[6][3]);
		spielfeldtisch.add(spielfeldzelle[7][4]);
		spielfeldtisch.add(spielfeldzelle[8][5]);
		spielfeldtisch.add(spielfeldzelle[7][6]);
		spielfeldtisch.add(spielfeldzelle[6][7]);
		spielfeldtisch.add(spielfeldzelle[5][8]);
		spielfeldtisch.add(spielfeldzelle[4][7]);
		spielfeldtisch.add(spielfeldzelle[3][6]);
		spielfeldtisch.add(spielfeldzelle[2][5]);
		spielfeldtisch.add(spielfeldzelle[3][4]);
		
		spielfeldstuhl.add(spielfeldzelle[4][4]);
		spielfeldstuhl.add(spielfeldzelle[5][1]);
		spielfeldstuhl.add(spielfeldzelle[6][2]);
		spielfeldstuhl.add(spielfeldzelle[7][3]);
		spielfeldstuhl.add(spielfeldzelle[8][4]);
		spielfeldstuhl.add(spielfeldzelle[7][5]);
		spielfeldstuhl.add(spielfeldzelle[6][6]);
		spielfeldstuhl.add(spielfeldzelle[5][7]);
		spielfeldstuhl.add(spielfeldzelle[4][6]);
		spielfeldstuhl.add(spielfeldzelle[3][5]);
		spielfeldstuhl.add(spielfeldzelle[2][4]);
		spielfeldstuhl.add(spielfeldzelle[3][3]);
		spielfeldstuhl.add(spielfeldzelle[4][2]);
		spielfeldstuhl.add(spielfeldzelle[5][3]);
		spielfeldstuhl.add(spielfeldzelle[6][4]);
		spielfeldstuhl.add(spielfeldzelle[9][5]);
		spielfeldstuhl.add(spielfeldzelle[8][6]);
		spielfeldstuhl.add(spielfeldzelle[7][7]);
		spielfeldstuhl.add(spielfeldzelle[6][8]);
		spielfeldstuhl.add(spielfeldzelle[5][9]);
		spielfeldstuhl.add(spielfeldzelle[4][8]);
		spielfeldstuhl.add(spielfeldzelle[3][7]);
		spielfeldstuhl.add(spielfeldzelle[2][6]);
		spielfeldstuhl.add(spielfeldzelle[1][5]);
		
		
		for(Spielzelle a:spielfeldtisch) {
            a.setBackground(Color.ORANGE);
            a.setTyp(Spielzelle.Typ.Tisch);
            a.setLand(Spielzelle.Land.DE);
            a.repaint();
            //a.setZellart(2);
            final int tischindex = spielfeldtisch.indexOf(a);
            a.addMouseListener(new MouseAdapter() {
            	@Override
            	public void mouseClicked(MouseEvent e) {
            		System.out.println("Tisch: "+tischindex);
            		stuhlnummer = tischindex;
            	}
            });
        }
        for(Spielzelle b:spielfeldstuhl) {
            b.setBackground(Color.RED);
            //b.setZellart(1);
            final int stuhlindex = spielfeldstuhl.indexOf(b);
            b.addMouseListener(new MouseAdapter() {
            	@Override
            	public void mouseClicked(MouseEvent e) {
            		System.out.println("Stuhl: "+stuhlindex);
            		tischnummer = stuhlindex;
            	}
            });
        }
   
	}
	
}

class Kartenstapel extends JPanel {
	public Kartenstapel() {
		setLayout(new GridLayout(5,2));
		Random rand = new Random();
		for(int i=0;i<10;i++) {
			JLabel label = new JLabel();
		    label.setBackground(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
		    label.setOpaque(true);
		    add(label);
		}
	}
}
 
class AufbauHilfe {
    public static GridBagConstraints createGridBagConstraints(int x, int y, int width, int height, int weightX, int weightY) {
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.gridx = x;
        constraints.gridy = y;
        constraints.gridwidth = width;
        constraints.gridheight = height;
        constraints.weightx = weightX;
        constraints.weighty = weightY;
 
        return constraints;
    }
 
    public static JLabel createRandomBackgroundLabel(String text) {
        Random rand = new Random();
        JLabel label = new JLabel(text);
        label.setBackground(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
        label.setOpaque(true);
 
        return label;
    }
}```

So wie es da steht, klappt das schon einmal alles! :) Also die Tische und Stühle werden alle generiert, je nachdem was es ist in Orange oder Rot.
Man schaue dazu in die beiden for-each-Schleifen:
```for(Spielzelle a:spielfeldtisch) {
            a.setBackground(Color.ORANGE);
            a.setTyp(Spielzelle.Typ.Tisch);
            a.setLand(Spielzelle.Land.DE);
            a.setGeschlecht(Spielzelle.Geschlecht.Frau);
            a.repaint();
            final int tischindex = spielfeldtisch.indexOf(a);
            a.addMouseListener(new MouseAdapter() {
            	@Override
            	public void mouseClicked(MouseEvent e) {
            		System.out.println("Tisch: "+tischindex);
            		stuhlnummer = tischindex;
            	}
            });
        }
        for(Spielzelle b:spielfeldstuhl) {
            b.setBackground(Color.RED);
            final int stuhlindex = spielfeldstuhl.indexOf(b);
            b.addMouseListener(new MouseAdapter() {
            	@Override
            	public void mouseClicked(MouseEvent e) {
            		System.out.println("Stuhl: "+stuhlindex);
            		tischnummer = stuhlindex;
            	}
            });
        }```

War natürlich auch nur ein Platzhalter, bis ich das mit den Bildern hinkriege.
Nun habe ich bei a einmal setTyp und setLand eingetippt. Es soll ein Tisch sein und das Land bei allen einfach mal DE. Und dann noch ein Beispielgeschlecht.
Und sehe da: es läuft alles! :)

Perfekt! Also mein Beispiel geht. Nun muss ich mir natürlich noch meine Bilder zurechtrücken und die Methoden dazu schreiben. Und ein wenig für Ordnung sorgen, sieht für's erste noch ziemlich chaotisch aus. Vielen Lieben Dank aber erst einmal! :) 

Schöne Grüße
Lukas

Hallo Leute,

ich habe nochmal eine kleine Frage an euch.
Das ganze funktioniert sehr gut, die Bilder werden ordnungsgemäß geladen und alles funktioniert, wie es soll.
Jedoch gibt es ein Problem.
Java lädt. Und lädt. Und lädt. Ja, die Bilder sind nicht wenige. Deshalb braucht der eine ganze Weile zum Laden.
Wenn man einmal in den Quellcode der Klasse reinguckt, fällt aber folgendes auf:


import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;


public class Spielzelle extends JPanel {
	
	public static enum Typ {Leer, Stuhl, Tisch};

	private Typ t;
	private BufferedImage i;
	private Stuhl st;
	private Tisch ti;
	 
	public Spielzelle(Typ t) {
	    setTyp(t);
	}
	 
	public Typ getTyp() {
	    return t;
	}
	 
	public void setTyp(Typ t) {
	    if(t != this.t) {
	    	i = null;
	    }
	    this.t = t;
	}
	 
	public Stuhl getSt() {
		return st;
	}

	public void setSt(Stuhl st) {
		this.st = st;
	}

	public Tisch getTi() {
		return ti;
	}

	public void setTi(Tisch ti) {
		this.ti = ti;
	}

	protected void paintComponent(Graphics gr) {
		super.paintComponent(gr);
		URL url = null;
		if(t.equals(Typ.Leer)) {
			
		}else if(t.equals(Typ.Stuhl)) {
			if(this.getSt().getGast()!=null) {
				try{
					url = new URL(BaseURL.getJarBase(Spielfeld.class), "./gastkarten/gast_"+this.getSt().getGast().land+"_"+this.getSt().getGast().geschlecht+".jpg");
					i = ImageIO.read(url);
				}catch(MalformedURLException e) {
				}catch(IOException e) { }
			}else{
				try {
					url = new URL(BaseURL.getJarBase(Spielfeld.class), "./layout/stuhl_leer.jpg");
					i = ImageIO.read(url);
				}catch(MalformedURLException e) {
				}catch(IOException e) { }
			}
		}else if(t.equals(Typ.Tisch)) {
			if(this.getTi().getLand()!=null) {
				try{
					url = new URL(BaseURL.getJarBase(Spielfeld.class), "./tischkarten/tisch_"+this.getTi().getLand().land+".jpg");
					i = ImageIO.read(url);
				}catch(MalformedURLException e) {
				}catch(IOException e) { }
			}else{
				try {
					url = new URL(BaseURL.getJarBase(Spielfeld.class), "./layout/tisch_leer.jpg");
					i = ImageIO.read(url);
				}catch(MalformedURLException e) {
				}catch(IOException e) { }
			}
		}
		if(i!=null) {
	    	gr.drawImage(i,0,0, getWidth(), getHeight(), null);
	    }
	}
}```

Der lädt alle Tische und Gäste, insofern sie gefüllt sind.
Wenn nicht sind da Platzhalter. Standardmäßig also 36 Platzhalter. Und da sind wir auch schon bei einem Problem meiner Meinung nach.
Der lädt immer und immer wieder das gleiche Bild. Komplett neu. Kann man das laufzeittechnisch nicht irgendwie verbessern?
Fällt da jemandem etwas dazu ein? Dass der das nur einmal lädt und dann so oft wie benötigt einfügt?
Ich hatte es schon damit versucht, es ganz oben zu definieren, aber dann fiel mir ein, das sind ja alles einzelne JPanel (11 mal 11), dann lädt der die ja trotzdem in jedem Einzeln.

Ich wäre über Lösungswege, die meine Laufzeit verbessern sehr dankbar!

Gruß
Lukas. :)

Klar, lade das Bild nur einmal :wink:
Sobald ein Bild geladen wurde solltest du dir das in eine geeignete Datenstruktur (bspw. Map) legen. Wenn dann ein Bild angefordert wird schaust du zuerst in der Map nach ob dort schon das Bild vorhanden ist. Falls ja, nimmst du das. Falls nein lädst du das Bild aus dem Dateisystem und legst es in die Map.
Das ganze lässt sich prima in einer eigenen Klasse kapseln.

Natürlich geht das. In Anlehnung zu meiner letzten Klasse, kann man die Bilder cachen. Aber ich würde von mehreren Verzeichnissen (also z.B. “./gastkarten” usw.) absehen und statt dessen ein weiteres Enum einsetzen und für jede Konstellation Bilder mit “null” im Namen speichern. Hinzu kommt noch ein “defaultImage”, welches für ausgelassene Konstellationen geladen wird.
Das Ganze sieht dann ungefähr so aus:

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.TreeMap;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

class Spielfeld {
	// dummy
}

public class Spielzelle extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 2380390353994983565L;

	private static final Map<String, BufferedImage> CACHE = new TreeMap<>();

	private static final BufferedImage DEFAULT_IMAGE;

	static {
		BufferedImage bi = null;
		try {
			URL url = new URL(BaseURL.getJarBase(Spielfeld.class), "defaultImage.jpg");
			bi = ImageIO.read(url);
			if(bi == null) {
				bi = ImageIO.read(url);
			}
		} catch (MalformedURLException e) {
			// react as you like
		} catch (IOException e) {
			// react as you like
		}
		DEFAULT_IMAGE = bi;
	}

	public enum Geschlecht {
		Mann, Frau
	}

	public enum Land {
		DE, FR, GB, US, TR, IN, CN, RU, ES, CU, CF, IT, JOKER
	}

	public enum Typ {
		Stuhl, Tisch
	}

	private Land l;
	private Geschlecht g;
	private Typ t;
	private BufferedImage i;

	public Spielzelle() {
		this(null, null, null);
	}

	public Spielzelle(Geschlecht g, Land l, Typ t) {
		setLand(l);
		setGeschlecht(g);
		setTyp(t);
	}

	public Geschlecht getGeschlecht() {
		return g;
	}

	public Land getLand() {
		return l;
	}

	public Typ getTyp() {
		return t;
	}

	public void setGeschlecht(Geschlecht g) {
		if (g != this.g) {
			i = null;
		}
		this.g = g;
	}

	public void setLand(Land l) {
		if (l != this.l) {
			i = null;
		}
		this.l = l;
	}

	public void setTyp(Typ t) {
		if (t != this.t) {
			i = null;
		}
		this.t = t;
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (i == null) {
			i = loadImage(this.l, this.g, this.t);
		}
		g.drawImage(i, 0, 0, getWidth(), getHeight(), null);
	}

	private synchronized static BufferedImage loadImage(Land l, Geschlecht g, Typ t/*, weitere Attribute */) {
		String land = (l != null)? l.toString() : "null";
		String geschlecht = (g != null)? g.toString() : "null";
		String typ = (t != null)? t.toString() : "null";
		// weitere Strings...
		// nicht vergessen, sie an den Dateinamen vor ".jpg" zu hängen
		String key = typ + "_" + land + "_" + geschlecht + ".jpg";
		BufferedImage bi = CACHE.get(key);
		if(bi == null) {
			try {
				URL url = new URL(BaseURL.getJarBase(Spielfeld.class), key);
				bi = ImageIO.read(url);
			} catch (MalformedURLException e) {
				// react as you like
			} catch (IOException e) {
				// react as you like
			}
			if(bi == null) {
				bi = DEFAULT_IMAGE;
			}
			CACHE.put(key, bi);
		}
		return bi;
	}
}```
Gekapselt habe ich das Ganze jetzt mal nicht, damit es in eine Klasse passt und somit als KSKB realisiert werden kann. ;)