# "Animation" funktioniert nur bedingt.



## Kiola (29. Nov 2008)

Hey

Ich würde gerne mehrere Bilder schnell hintereinander zeichnen, nur leider funktioniert dies nur wenn ich NICHT "extends JPanel" mache. Doch das brauche ich in meinem Programm.
Habe mal zwei Testprogramme geschrieben:
Das hier funktioniert:


```
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class AniFunktioniert extends JFrame{
	private BufferedImage h,eins,zwei;
	private BufferedImage feld[];
	
	public AniFunktioniert () {
		
		h=loadPics("hintergrund.jpg");
		eins=loadPics("1.png");
		zwei=loadPics("2.png");
		feld= new BufferedImage[2];
		feld[0]=eins;
		feld[1]=zwei;
		
		this.setPreferredSize(new Dimension(500,500));
		Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
		this.setResizable(false);
		this.setLocation((resolution.width - this.getSize().width)/7, 
				(resolution.height - this.getSize().height)/7);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.pack();
		this.setVisible(true);	
		this.repaint();
	}

	
	private BufferedImage loadPics(String path){
		BufferedImage source = null;
		URL pic_url= getClass().getClassLoader().getResource(path);
		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return source.getSubimage(0, 0, source.getWidth(), source.getHeight());
	}
	
	public void paint (Graphics g) {
		g.drawImage(h,0,0,this);
		aniZeichnen(g);
	}
	
	private void aniZeichnen(Graphics g) {
		for(int i = 0; i <2;i++){
			g.drawImage(feld[i],100,100,this);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		new AniFunktioniert();
	}
}
```


und das hier leider nicht =(


```
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;


public class extendsJPanel extends JPanel{
	private JFrame frame;
	BufferedImage h,eins,zwei;
	BufferedImage feld[];

	public extendsJPanel () {

		h=loadPics("hintergrund.jpg");
		eins=loadPics("1.png");
		zwei=loadPics("2.png");
		feld= new BufferedImage[2];
		feld[0]=eins;
		feld[1]=zwei;
		
		feld= new BufferedImage[2];
		feld[0]=eins;
		feld[1]=zwei;
		this.setPreferredSize(new Dimension(500,500));
		Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
		frame= new JFrame();
		frame.setResizable(false);
		frame.setLocation((resolution.width - frame.getSize().width)/7, 
				(resolution.height - frame.getSize().height)/7);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);	
		frame.repaint();
	}
	
	private BufferedImage loadPics(String path){
		BufferedImage source = null;
		URL pic_url= getClass().getClassLoader().getResource(path);
		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return source.getSubimage(0, 0, source.getWidth(), source.getHeight());
	}
	
	public void paint (Graphics g) {
		g.drawImage(h,0,0,this);
		aniZeichnen(g);
	}
	
	private void aniZeichnen(Graphics g) {
		System.out.println("23");
		for(int i = 0; i <2;i++){
			g.drawImage(feld[i],100,100,this);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	public static void main(String[] args) {
		new extendsJPanel();
	}
}
```

kann mir jemand sagen woran das liegen könnte?

Danke schonmal im Voraus!


----------



## Quaxli (29. Nov 2008)

Wunder mich, daß es überhaupt funktioniert. Ein paar Dinge die mir aufgefallen sind:

1. in den paint-Methoden fehlen die super-Aufrufe, also:


```
public void paintComponent (Graphics g) {
      super.paintComponent(g);
      g.drawImage(h,0,0,this);
      //aniZeichnen(g);
   }
```

Mal abgesehen davon, daß man in Swing paintComponent überschreiben sollte.

2. Der Thread der die Animation startet sollte nicht aus der überschriebenen paintComponent-Methode gestartet werden.

3. mach nach dem Thread.sleep(..) mal einen repaint() - am Besten auf den ganzen Frame


----------



## Kiola (29. Nov 2008)

Also

habe die paint-Methode in die paintComponent umbenannt und den super-Aufruf gemacht.
Wo soll ich denn den Thread starten lassen?

frame.repaint() nach dem Thread.sleep macht das ganze leider nur noch schlimmer. Wenn ich jetzt das ganze Fenster bewege "verwischt" alles.

hier mein veränderter Code:


```
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;


public class extendsJPanel extends JPanel{
	private JFrame frame;
	BufferedImage h,eins,zwei;
	BufferedImage feld[];

	public extendsJPanel () {

		h=loadPics("hintergrund.jpg");
		eins=loadPics("1.png");
		zwei=loadPics("2.png");
		feld= new BufferedImage[2];
		feld[0]=eins;
		feld[1]=zwei;
		feld= new BufferedImage[2];
		feld[0]=eins;
		feld[1]=zwei;
		this.setPreferredSize(new Dimension(500,500));
		Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
		frame= new JFrame();
		frame.setResizable(false);
		frame.setLocation((resolution.width - frame.getSize().width)/7, 
				(resolution.height - frame.getSize().height)/7);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);	
		frame.repaint();
		
	}
	
	private BufferedImage loadPics(String path){
		BufferedImage source = null;
		URL pic_url= getClass().getClassLoader().getResource(path);
		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return source.getSubimage(0, 0, source.getWidth(), source.getHeight());
	}
	
	public void paintComponent (Graphics g) {
		super.paintComponent(g);
		g.drawImage(h,0,0,this);
		aniZeichnen(g);
		
	}
	
	private void aniZeichnen(Graphics g) {
		for(int i = 0; i <2;i++){
			g.drawImage(feld[i],100,100,this);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
//			frame.repaint();
		}
		
	}
	public static void main(String[] args) {
		new extendsJPanel();
	}
}
```


----------



## SlaterB (29. Nov 2008)

> 2. Der Thread der die Animation startet sollte nicht aus der überschriebenen paintComponent-Methode gestartet werden. 

bisher gibts ja noch gar keinen Thread 

mich wundert auch dass es beim JFrame geht, 
halbwegs erlaubt wäre aber nur etwas in der Art von:


```
class ExtendsJPanel extends JPanel {
	private JFrame frame;
	BufferedImage h, eins, zwei;
	BufferedImage feld[];
	private int pictureToPaint = 1;

	public ExtendsJPanel() {

		h = loadPics("back.png");
		eins = loadPics("1.png");
		zwei = loadPics("2.png");
		feld = new BufferedImage[2];
		feld[0] = eins;
		feld[1] = zwei;

		this.setPreferredSize(new Dimension(500, 500));
		Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
		frame = new JFrame();
		frame.setResizable(false);
		frame.setLocation((resolution.width - frame.getSize().width) / 7,
				(resolution.height - frame.getSize().height) / 7);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);
		aniZeichnen();
	}

	private BufferedImage loadPics(String path) {
		BufferedImage source = null;
		URL pic_url = getClass().getClassLoader().getResource(path);
		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return source.getSubimage(0, 0, source.getWidth(), source.getHeight());
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawImage(h, 0, 0, this);
		g.drawImage(feld[pictureToPaint], 100, 100, this);
	}

	private void aniZeichnen() {
		Runnable r = new Runnable() {
			public void run() {

				for (int i = 0; i < 12; i++) {
					System.out.println("i: " + i);
					pictureToPaint = (i % 2);
					try {
						Thread.sleep(400);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					repaint();
				}
			}
		};

		new Thread(r).start();
	}

	public static void main(String[] args) {
		new ExtendsJPanel();
	}
}
```

beim JFrame paint() zu überschreiben führt bei mir zu Flackern,
JPanel ist schon die richtige Ecke


------

edit: 
da aniZeichnen() hier vom main-Thread aus ausgerufen wird, ginge es auch ohne neuen Thread,
Hauptsache, die GUI muss diese Aufgabe nicht übernehmen (aus paint oder aus einem ActionListener aufgerufen,
dann wäre ein neuer Thread nötig)


----------



## Kiola (29. Nov 2008)

hey danke!!
das funktioniert ja!!!
obwohl das mit dem Runnable usw kompliziert aussieht. Wäre ich niemals drauf gekommen..


----------



## SlaterB (29. Nov 2008)

viel wichtiger ist die Erkenntnis, dass die Schleife nur eine int-Variable setzt und dann repaint() aufruft,
ist allerdings auch oft mit einem Thread verbunden..


----------



## Kiola (29. Nov 2008)

meinst du mit dem "dass die Schleife nur eine int-Variable setzt", dass sie nicht an der stelle drawImage aufruft?
Ist das das Problem?


----------



## SlaterB (29. Nov 2008)

genau, denn entweder bedeutet das, dass die Schleife von paint() aus ausgeführt wird, was im Falle des JPanels dazu führt, dass nix angezeigt ist bis die Schleife und damit auch paint() fertig ist
(wieso es bei JFrame einigermaßen geht ist verwunderlich)

oder es bedeutet, dass parallel zu paint() noch jemand anders rummalt,
die beiden sich damit in die Quere kommen können, auch nicht schön


----------



## Quaxli (29. Nov 2008)

SlaterB hat gesagt.:
			
		

> bisher gibts ja noch gar keinen Thread



Stimmt ... hab' ich mir irgendwie eingebildet  keine Ahnung was ich da wieder gesehen habe  ???:L


----------

