Zeichnen von Bildern auf JPanel aus eigenem Objekt

bounce

Mitglied
Hallo,

ich bin hier regelrecht am verzweifeln.
Derzeit arbeite ich an einem Projekt mit dem Ziel eine spielfähige Version des Klassikers
"Sokuban" nachzubauen.
Jedoch zeichnet mein JPanel meine Bilder einfach nicht.
Ich erstelle mir ein 2D Array aus MapItems (wie Spieler//Mauer//Kiste), welche jeweils ein
Bild speichern und dieses über getImage() zurückliefern.
Java:
package de.fhh.ms.dt;
import java.awt.Image;



public abstract class MapItem 
{
	private Image image;
	
	public MapItem(Image images)
	{
		this.image=image;
	}
	
	public abstract boolean isMoveable();
	
	public abstract boolean isWalkable();
	
	public Image getImage()
	{
		return image;
	}

}
Wenn ich jetzt in meinem Panel die PaintComponent() überschreibe und dort:

Java:
@Override protected void paintComponent(Graphics g)
	    {
	    	super.paintComponent(g);
	        for(int a=0;a<currentMap.length;a++)
			{
				y=60*a;
				for(int z=0;z<currentMap[0].length;z++)
				{
					x=60*z;
					if(currentMap[a][z]!=null)
					{	
					   g.drawImage(currentMap[a][z].getImage(), x, y, null);
					   //g.drawImage(temp, x, y, null);
					}
				}
			}
ausführe, zeichnet er mir gar nichts.
Meine Bilder habe ich schon versucht über zwei verschiedene Wege bekannt zu geben:
Java:
 wallImage=  Toolkit.getDefaultToolkit().getImage( "wall.jpg" );
	   //wallImage = new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
, jedoch führte bislang nichts zum gewünschten Erfolg.
Hoffentlich könnt ihr mir sagen, was ich da falsch mache.

Gruß

bounce
 
male zunächst nur mit drawLine() irgendwas, ist das nicht zu sehen?
evtl. hat das Panel eine Größe von nur 1 Pixel weil keine Komponenten drin sind,
sofern das Panel überhaupt korrekt in die GUI eingefügt ist,
Layout, setPreferredSize()?

wenn Zeichenbefehle zu sehen sind, dann ist möglich dass das Bild nicht korrekt geladen wird,
was liefert new File("wall.jpg").exists(); ?
sind die Image-Objekte != null, kann man dort Höhe/Breite abfragen?
 
wenn ich eines meiner Bilder lokal in der Klasse meines JPanel deklariere
zeichnet er mir das Bild korrekt, also:
Java:
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

import de.fhh.ms.dt.MapItem;

public class DrawImages extends JPanel
{
	   private MapItem[][] currentMap;
	   private Dimension size;
	   private int x=0;
	   private int y=0;
	   private Image temp;
	   
	    public DrawImages(MapItem[][] currentMap)
	    {
	        size = new Dimension();
	        this.currentMap=currentMap;
	        temp = new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
	        size.width = 600;
	        size.height = 600;
	        setPreferredSize(size);
	    }

	    @Override public void paint(Graphics g)
	    {
	    	//g=this.getGraphics();
	       // Graphics2D g2d = (Graphics2D) g;
	        for(int a=0;a<currentMap.length;a++)
			{
				y=60*a;
				for(int z=0;z<currentMap[0].length;z++)
				{
					x=60*z;
					if(currentMap[a][z]!=null)
					{	
					   System.out.println("hier kommt er an");
					   //temp=currentMap[a][z].getImage();
					   //g.drawImage(currentMap[a][z].getImage(), x, y, null);
					   g.drawImage(temp, x, y, null);
					}
				}
			}
	    }

	    public static void main(String[] args)
	    {
	    	Map level = new Map();
	        level.createlevel(1);
	        JFrame frame = new JFrame();
	        frame.setTitle("Honeymug");
			frame.setSize(800, 600);
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			frame.setPreferredSize(new java.awt.Dimension(800, 600));
	        frame.add(new DrawImages(level.getMap()));
	        frame.pack();
	        frame.setVisible(true);
	        
	    }
}
 
paintComponent statt paint ist schon zu empfehlen,
baue Schritt um Schritt alles zum obigen Programm um,

den Fehler vermute ich bei
> new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
vs
> Toolkit.getDefaultToolkit().getImage( "wall.jpg" );

wenn das obige geht dann nimm doch immer das,
allgemein wird dort exakt im Verzeichnis der .class-Datei gesucht (oder im Jar),
während der untere Befehl sich auf das Grundverzeichnis der Ausführung bezieht, abhängig davon von wo aus das Programm gestartet wird
 
paintComponent statt paint ist schon zu empfehlen,
baue Schritt um Schritt alles zum obigen Programm um,

den Fehler vermute ich bei
> new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
vs
> Toolkit.getDefaultToolkit().getImage( "wall.jpg" );

wenn das obige geht dann nimm doch immer das,
allgemein wird dort exakt im Verzeichnis der .class-Datei gesucht (oder im Jar),
während der untere Befehl sich auf das Grundverzeichnis der Ausführung bezieht, abhängig davon von wo aus das Programm gestartet wird

Ich habe die neueste Version auf meinem Laptop.
Dort habe ich bereits PaintComponent verwendet anstatt paint.
Der Versuch mit der Toolkit Variante war nur, um auszuschließen, dass es an der ImageIcon
Variante liegt.
Dennoch kein Erfolg, wie auch immer.
 
geh nochmal Schritt für Schritt meine Fragen im ersten Posting durch,
im Moment weiß niemand, welches Layout du im paintComponent-Programm verwendest,
ob auf diesem Laptop die jpg-Dateien vorhanden sind usw.
 
Die Frage bzgl. des Layouts kann ich dir nicht beantworten,
da ich mich damit nicht wirklich beschäftigt habe.
Die preferedsize für meinen JFrame liegt bei 800x600 und für
mein JPanel bei 600x600, wie oben aus dem Code zu ersehen.
Eine Linie zeichnet er mir problemlos mit
Java:
g.drawLine(0, 0, 200, 200);

Was mich gerade jedoch etwas verwundert,
Wenn ich
Java:
 @Override public void paintComponent(Graphics g)
	    {
	    	g.drawLine(0, 0, 200, 200);
	    	System.out.println(new File("plattform.jpg").exists());
	    }
ausführe, schreibt er mir zwei mal true, also wird wohl die paintComponent wohl
mehrfach aufgerufen.
 
Zuletzt bearbeitet:
du verwendest also das untere Programm auch für oben mit paintComponent, das ist doch schon eine Info,
JFrame verwendet übrigens BorderLayout, maximiert das einzige eingefügte Panel, in diesem Fall wäre eine PreferredSize gar nicht nötig, bzw. du kannst das Panel auch gar nicht so leicht kleiner machen als das Frame

-----

jetzt die Bilder suchen,
new File("wall.jpg"),
davon getAbsolutePath() ausgeben und im Dateisystem nachschauen ob der Pfad Sinn macht und dort Bilder sind,
mit exists() nachschauen ob Java die in der Hinsicht findet,
die erzeugen Image-Objekte anschauen wie beschrieben,

vielleicht bringt das Infos, ich muss jetzt eh weg
 
Aber das heißt ja zumindest, dass ich da keinen groben Denkfehler drin habe.
Dann werde ich mich wohl mal an meinen Dozenten wenden müssen.
Aber ich danke dir auf jeden Fall für deine Mühe, vielleicht fällt ja dennoch jemandem
etwas auf.
 
Eventuell hilft es jemandem, wenn ich ihm mein gesamtes Projekt schicke,
denn vielleicht liegt der Fehler an meinem Eclipse oder sonstiges.
 
ich denke bei dir lokal funktioniert es schon, nur auf dem Laptop nicht oder so?
minimale Unterschiede durch andere Installationen usw. sind immer denkbar und nur schwer aus der Ferne zu finden

oder hast du auf deinen beiden Rechnern unterschiedliche Programmversionen?
oder ist die ganze Zeit nur von einem Computer die Rede?


---

aber allgemein uploaden bzw. anbieten falls sich jemand meldet kannst du natürlich
 
Zuletzt bearbeitet von einem Moderator:
Tut mir leid, wenn ich da für etwas Verwirrung gesorgt habe.
Nein, das Problem ist, es funktioniert überhaupt ganz und gar niemals nicht und nichten.
Weder auf meinem Laptop, noch auf meinem Heimrechner.
Es kann schon sein, dass ich verschiedene Eclipse Versionen mit verschiedenen Java Versionen
auf den Rechnern laufen habe.
 
auch von mir ja falsch verstanden, also etwas zurück, zu
wenn ich eines meiner Bilder lokal in der Klasse meines JPanel deklariere
zeichnet er mir das Bild korrekt, also:
klappt dieses Einlesen nun oder nicht? in welcher Klasse oder mit welcher Methode ist doch erstmal egal,
kannst du irgendwo ein bzw. alle Bilder einlesen und korrekt auf den Bildschirm malen?
 
Wenn du oben einmal guckst klick kannst du sehen, dass ich da lokal in meiner
JPanel Klasse ein Image temp angelegt habe. Weiter unten in der paint() Methode wird es dann
gezeichnet, und das funktioniert auch, egal ob nun paint oder paintComponent.
Wenn ich aber nun ein Image-Objekt aus meinem Array zurückgegeben bekomme bleibt
das Panel unberührt.
 
wie in dein Array Images oder überhaupt Objekte kommen hast du bisher auch noch nicht gepostet,
also ja, dein Vorschlag, mehr Code hochzuladen oder eher hier zu posten würde helfen,

kodiere
Java:
temp = new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
array[0][0] = new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
und male sowohl das Array als auch die einzelne Variable direkt nebeneinander,
bzw. poste einfach was du hast, die Klasse Map mti createLevel() z.B., dann sieht man es vielleicht schon
 
Also gut.
Hier wird mein Level generiert:
Java:
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.ImageIcon;

import de.fhh.ms.dt.*;
public class Map
{
   private Image wallImage;
   private Image playerImage;
   private Image plattformImage;
   private Image mugImage;
   private MapItem[][] level;
   public Map()
   {
	   
   }
   
   public void createlevel(int i)
   {
	   wallImage=  Toolkit.getDefaultToolkit().getImage( "wall.jpg" );
	   //wallImage = new ImageIcon(this.getClass().getResource("wall.jpg")).getImage();
	   mugImage=  Toolkit.getDefaultToolkit().getImage( "honeymug.gif" );
	   //mugImage = new ImageIcon(this.getClass().getResource("honeymug.gif")).getImage();
	   plattformImage=  Toolkit.getDefaultToolkit().getImage( "plattform.jpg" );
	   //plattformImage = new ImageIcon(this.getClass().getResource("plattform.jpg")).getImage();
	   playerImage=  Toolkit.getDefaultToolkit().getImage( "player.jpg" );
	   //playerImage = new ImageIcon(this.getClass().getResource("player.jpg")).getImage();
	   switch(i)
	   {
	      case(1):
	      
		      level=new MapItem[10][10];
		      for(int a=0;a<10;a++)
		      {
	             for(int z=0;z<10;z++)
	             {
	            	level[a][z]=null;
	            	if(a==0||z==0||z==9||a==9)
	            	{
	                   level[a][z]=new Wall(wallImage);
	                   System.out.println("wand:"+z+" "+a);
	            	}
	            	if(a==3&&z==3||a==3&&z==4||a==4&&z==3||a==4&&z==4)
	            	{
	            		level[a][z]=new Mug(mugImage);
	            		System.out.println("honig:"+z+" "+a);
	            	}
	            	if(a==8&&z==1)
	            	{
	            		level[a][z]=new Spieler(playerImage);
	            		System.out.println("spieler:"+z+" "+a);
	            	}
	             }
		      }
		      break;
	      
	      default:
	      {
	    	  break;
	      }
	   }
   }
   
   public MapItem[][] getMap()
   {
	   return level;
   }
}

Hier die Oberklasse für meine MapItem Objekte:
Java:
package de.fhh.ms.dt;
import java.awt.Image;



public abstract class MapItem 
{
	private Image image;
	
	public MapItem(Image image)
	{
		this.image=image;
	}
	
	public abstract boolean isMoveable();
	
	public abstract boolean isWalkable();
	
	public Image getImage()
	{
		return image;
	}

}

und hier soll der ganze Spass dann angezeigt werden:
Java:
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

import de.fhh.ms.dt.MapItem;

public class DrawImages extends JPanel
{
	   private MapItem[][] currentMap;
	   private Dimension size;
	   private int x=0;
	   private int y=0;
	   private Image temp;
	   
	    public DrawImages(MapItem[][] currentMap)
	    {
	        //size = new Dimension();
	        this.currentMap=currentMap;
	        //temp = new ImageIcon(this.getClass().getResource("honeymug.gif")).getImage();
	        //size.width = 60;
	        //size.height = 60;
	        //setPreferredSize(size);
	    }

	    @Override protected void paintComponent(Graphics g)
	    {
	    	super.paintComponent(g);
	        for(int a=0;a<currentMap.length;a++)
			{
				y=60*a;
				for(int z=0;z<currentMap[0].length;z++)
				{
					x=60*z;
					if(currentMap[a][z]!=null)
					{	
					   g.drawImage(currentMap[a][z].getImage(), x, y, null);
					   //g.drawImage(temp, x, y, null);
					}
				}
			}
	    }

	    public static void main(String[] args)
	    {
	    	Map level = new Map();
	        level.createlevel(1);
	        JFrame frame = new JFrame();
	        frame.setTitle("Honeymug");
			frame.setSize(800, 600);
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			frame.setPreferredSize(new java.awt.Dimension(800, 600));
	        frame.add(new DrawImages(level.getMap()));
	        frame.pack();
	        frame.setVisible(true);
	        
	    }
}
 
siehst du etwas wenn du ein wenig wartest und dann die Größe des Fensters änderst?
so ist es bei mir mit einem Testbild

liegt wohl wirklich am Laden, eigentlich kenne ich das, war verwirrt in diesem Thema, mal zu sehen, mal nicht..,

----

verwende zum Laden
> new ImageIcon("wall.jpg").getImage();

der Code im Konstruktor dort ist in etwa:
Java:
    /**
     * Creates an ImageIcon from the specified file. The image will
     * be preloaded by using MediaTracker to monitor the loading state
     * of the image.
     * @param filename the name of the file containing the image
     * @param description a brief textual description of the image
     * @see #ImageIcon(String)
     */
    public ImageIcon(String filename, String description) {
	image = Toolkit.getDefaultToolkit().getImage(filename);
        if (image == null) {
            return;
        }
	this.filename = filename; 
        this.description = description;
	loadImage(image);
    }

    /**
     * Loads the image, returning only when the image is loaded.
     * @param image the image
     */
    protected void loadImage(Image image) {
	synchronized(tracker) {
            int id = getNextID();

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

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

Bilder müssen erst geladen werden, das dauert seine Zeit, bei vielen Bildern hättest du auf diesem Weg evtl. unschöne Wartezeiten,
dafür vermeidest du Anzeigefehler wenn das Bild noch nicht da ist, für kleine Bildmengen sicher geeignet
 
Ich drehe durch... jetzt hat er es auf einmal gemalt, ohne das ich etwas verändert habe.
So langsam komme ich mir etwas verschaukelt vor.

Wenn es so bleibt danke ich dir für deine Anstrengungen.🙂
 
Zuletzt bearbeitet:

Zurück
Oben