Image laden und Speichern - Image wird auf JPanel nicht angezeigt

Crite

Mitglied
Hi Leute,
ich hab die Klassen TrainIRW und ImageMenu.
Mein Ziel ist es, über den Menubutton "load Image" das Bild in mein JPanel zu bekommen.
Mit dem "save Image" speicher ich das Bild z.B auf meinem Desktop.
Nun habe ich das Problem, dass er mir das Bild auf meinem JPanel NICHT anzeigt, aber speichern geht.
Wenn ich aber das Objekt TrainIRW übergebe und nicht das Image von TrainIRW, dann funktionierts.

Nun würde ich gerne wissen, warum das so ist.

Java:
public class TrainIRW extends JPanel{
	
	private final static long serialVersionUID = 1L;
	protected Image img;
	
	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawImage(img, 0, 0, null);
	}
	
	public static void main(String[] args) {
		
		TrainIRW tIRW = new TrainIRW();
		
		JFrame frame = new JFrame("Tain IRW");
		frame.setJMenuBar(new ImageMenu(tIRW));
		Container con = frame.getContentPane();
		con.add(tIRW);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(800, 600);
		frame.setVisible(true);
	}
	
}

class ImageMenu extends JMenuBar{
	
	private final static long serialVersionUID = 1L;
	protected BufferedImage bi;
	protected File file;
	
	public ImageMenu(TrainIRW tIRW){
		JMenu menu = new JMenu("File");
		
		JMenuItem loadItem = new JMenuItem("load Image");
		JMenuItem saveItem = new JMenuItem("save Image");
		
		loadItem.addActionListener(e->{
			loadImg(tIRW.img); //hier nur tIRW, dann funktionierts
			tIRW.repaint();
		});
		
		saveItem.addActionListener(e->{
			saveImg();
		});
		
		menu.add(loadItem);
		menu.add(saveItem);
		add(menu);
	}
	
	private void loadImg(Image img){ //hier TrainIRW  tirw übergeben
		try{
			file = new File("...png"); //Musterpath
			bi = ImageIO.read(file);
					
			System.out.println("Image successfully loaded from " + file.getPath());
		}catch(IOException e){
			e.printStackTrace();
		}
		img = bi; //hier tIRW.img, dann funktionierts
	}
	
	private void saveImg(){
		file = new File("c:..."); //Musterpath
		try{
			ImageIO.write(bi, "png", file);
			
			System.out.println("Image successfully saved in " + file.getPath());
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}

Ich hoffe, da blickt jemand durch meinen Code, auch wenn die Variablennamen nicht gut gewählt sind und die Struktur nicht allzu sauber ist.
 
Zuletzt bearbeitet von einem Moderator:
Es liegt daran dass java kein direktes Call by Reference hat. Du versuchst das übergebene Image Objekt durch ein anderes zu überschreiben
Code:
img = bi; //hier tIRW.img, dann funktionierts
. Da aber nur eine Kopie der Reference an die "loadImg()" Methode übergeben wird, ändert sich das Ursprungsobjekt nicht.
Dass es mit einem übergebenen Panel Objekt funktioniert liegt daran, dass zwar auch hier eine Kopie der Reference übergeben wird, du aber eine Eigenschaft des Panel Objektes veränderst. Nämlich das Image darin.

Man kann also übergebene Objekte verändern (Membervariablen ändern/oder per Methoden zb. setter) und diese Änderungen sind auch für anderen Stellen ersichtlich, die dieses Objekt kennen.
Man kann aber nicht das komplette Objekt durch ein neues ersetzen. (Man "kann" natürlich schon, aber alle anderen Stellen, die das Ursprungs Objekt kennen bekommen davon nichts mit).


Dieses Thema ist schon etwas komplex. Wenn ich also mit meiner Begriffswahl falsch liege, möge man mich bitte darauf hinweisen.
 
Es liegt daran dass java kein direktes Call by Reference hat. Du versuchst das übergebene Image Objekt durch ein anderes zu überschreiben
Code:
img = bi; //hier tIRW.img, dann funktionierts
. Da aber nur eine Kopie der Reference an die "loadImg()" Methode übergeben wird, ändert sich das Ursprungsobjekt nicht.
Dass es mit einem übergebenen Panel Objekt funktioniert liegt daran, dass zwar auch hier eine Kopie der Reference übergeben wird, du aber eine Eigenschaft des Panel Objektes veränderst. Nämlich das Image darin.

Man kann also übergebene Objekte verändern (Membervariablen ändern/oder per Methoden zb. setter) und diese Änderungen sind auch für anderen Stellen ersichtlich, die dieses Objekt kennen.
Man kann aber nicht das komplette Objekt durch ein neues ersetzen. (Man "kann" natürlich schon, aber alle anderen Stellen, die das Ursprungs Objekt kennen bekommen davon nichts mit).


Dieses Thema ist schon etwas komplex. Wenn ich also mit meiner Begriffswahl falsch liege, möge man mich bitte darauf hinweisen.

So ganz ist mir das nicht klar. Ich hab angenommen, dass jedes Object in Java ein Pointer ist.
Da ich in meinem Fall nur über Objects gehe, müsste ich doch bei Image schon auf die Adresse von TrainIRW zugreifen können.
 
Wie gesagt ich weiss nicht genau wie man die übergebenen "Objekte" jetzt bezeichnen soll. Pointer/Referenzen/Kopien von Referenzen... Keine Ahnung. Es ist aber wohl so, dass du die Original Objekte von jeden Ort aus verändern kannst; Du kannst aber nicht auf deren Bereich im Speicher ein neues erstellen.
Wenn dein übergebenes Image jetzt eine Methode hätte wie: "replaceImageDataWithDataFromNewImage(Image newImage)" dann würde ein Aufruf:
Code:
img.replaceImageDataWithDataFromNewImage(bi);
funktionieren.

Edit:
Wie gesagt, Ich kenne mich mit dem Speichermanagemant von Java nicht wirklich aus. Ich schreibe hier nur wie es sich für mich darstellt.
 
Zuletzt bearbeitet:
Beispiel:

Java:
public class Person {
   public String name;

   public Person(String name) {
      this.name = name;
   }
}

......

public static void benennePersonUm(Person p) {
   p.name = "Gerhard";
}

public static void erzeugeNeuePerson(Person p) {
   p = new Person("Crite");
}

......

public static void main(String[] args) {
   Person p1 = new Person("Fritz");
   System.out.println(p1.name); // Fritz
   benennePersonUm(p1);
   System.out.println(p1.name); // Gerhard
   erzeugeNeuePerson(p1);
   System.out.println(p1.name); // Gerhard
}

Wir haben hier zwei Methoden "benennePersonUm" und "erzeugeNeuePerson", welche jeweils ein Objekt der Klasse Person erwarten.

In der lokalen Variable "p1" der main-Methode wird nur die Referenz auf das Objekt gespeichert.
Wenn man nun "p1" an eine Methode übergibst, wird eine Kopie dieser Referenz erzeugt.
In einer der beiden Methoden kannst man den "Inhalt" dieses Objektes ohne Probleme verändern (siehe Methode "benennePersonUm").
Aber man kannst nicht an der Speicherstelle (wo dein Referenz hinzeigt) ein komplett neues Objekt erstellen! (siehe Methode "erzeugeNeuePerson").

In der Methode "erzeugeNeuePerson" wird ein neues Objekt der Klasse Person erzeugt. Diese Objekt belegt im Speicher einen komplett neuen Bereich.
Regel: ein neues Objekt mit "new [Konstruktor](....)" erzeugen belegt immer neuen Speicherplatz!
Der Parameter der Methode "erzeugeNeuePerson" bekommt dabei die Referenz auf diese neues Objekt zugewiesen.

Die lokale Variable der main-Methode bleibt davon unbeeinträchtigt.

Ich hoffe dieses Beispiel inkl. Erklärung macht es etwas verständlicher.
 

Zurück
Oben