# Repaint() in Schleifen, Threads



## rix (2. Nov 2012)

Immer noch der Noob hier. Ich arbeite immer noch an meinem Mandelbrot-Programm. Weil das Ding bei großen Auflösungen extrem lange braucht, möchte ich das Bild in Stücken malen (damit die User sehen, dass es voran geht und das Programm sich nicht verabschiedet hat. Das geht, an und für sich, mit einem repaint(xstart,ystart,width,height:int).

Aber das geht nicht in Schleifen, wegen eines Threadproblems (ich denke, ich hab nur so halb verstanden, worum es dabei geht).

Ich habe versucht, das ganze mal runterzubrechen. In dem folgenden Programm sollten am Ende mehrere Rechtecke nebeneinander erscheinen, nachdem geklickt wurde (in diesem Fall ginge das natürlich auch durch eine Schleife in der paint-Methode, aber das ist ja nicht das Ziel des ganzen  ).

Könnt ihr mir bitte erklären, was ich falsch mache?

(Oder mir hilfreiche Rückfragen stellen, oder so; bin für jede Hilfe dankbar.)


```
package test1;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
 
/**
* @author rix
*
**/
public class Test1 extends JPanel implements MouseListener{
   
    public static void main(String[] args) {
        Test1 mandel;
        mandel = new Test1();
    }
   
    /* Global vars */
    private int width;
    private int height;
    private int xwidth,yheight,xstart,ystart;
    private JFrame frame;
    
     
    Test1(){
        
        width = 400;
        height = 300;
        
        xstart = 50;
        ystart = 50;
        yheight = 250;
        xwidth = 100;
        
        /* Generate Frame */
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new MyComponent());
        frame.setSize(width, height);
        frame.getContentPane().setBackground(Color.BLACK);
        frame.addMouseListener(this);
       
        frame.setVisible(true);
        
    }
 
    /*Mouse event*/
    @Override
    public void mouseClicked(MouseEvent me) {  
        
        myRepaint();
        
    } 
    
    @Override
    public void mousePressed(MouseEvent me) {    }
 
    @Override
    public void mouseReleased(MouseEvent me) {    }
 
    @Override
    public void mouseEntered(MouseEvent me) {    }
 
    @Override
    public void mouseExited(MouseEvent me) {    }
 
 
    class MyComponent extends JComponent {
 
        @Override
        public void paintComponent(Graphics g) {
           
            super.paintComponent( g );
            Graphics2D g2 = (Graphics2D) g;
           
            g2.setColor(Color.RED);
            g2.drawRect(xstart,ystart,xwidth,yheight);
          
        } 
    
    } 
    
    public void myRepaint() {
            
            new Thread(){
                @Override
                public void run() {
                    while (xstart <= width) {
                    xstart += xwidth+1;
                    frame.repaint(xstart,ystart,xwidth+3,yheight+1);
                    }
                
                }
                
            }.start();
            
            
        }
}
```


----------



## vanny (2. Nov 2012)

gib doch mal ein paar sysouts dazu, dann wirst du merken, das dein Thread garnichts tut.^^


----------



## rix (3. Nov 2012)

Wie meinst Du das? Alles, was in run() steht, wird ja ausgeführt. Nur wird repaint() nach wie vor nicht sofort ausgeführt, sondern wie immer erst nachdem die Schleife durch ist.


----------



## vanny (3. Nov 2012)

Ich verstehe auch deine Innerclass nicht ganz.
Mal ein Beispiel, wie ich daran gehen würde:

```
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class ZeichenTest extends JPanel{
	

	private static final long serialVersionUID = 1L;
	private int xTile, yTile, renderCountX, renderCountY, colorCount; 
	private Color[] skipColor = {Color.RED, Color.YELLOW, Color.BLACK};

	public ZeichenTest(int xTile, int yTile){
		this.xTile = xTile;
		this.yTile = yTile;
		
	}
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		g.setColor(skipColor[colorCount]);
		g.fillRect((renderCountX*this.getWidth()/xTile), (renderCountY*this.getHeight()/yTile), this.getWidth()/xTile, this.getHeight()/yTile);
	}
	
	public void nextRenderStep(){
		if(renderCountX<xTile-1){
			repaint();
			renderCountX++;
		}else if(renderCountX == xTile-1){
			renderCountX = 0;
			renderCountY++;
			repaint();
		}if(renderCountY == yTile){
			renderCountY = 0;
			colorStep();
		}
	}
	
	private void colorStep(){
		if(colorCount<skipColor.length-1){
			colorCount++;
		}else{
			colorCount = 0;
		}
	}
	
	public static void main(String[] args) {
		
		JFrame fr = new JFrame("TestFrame");
		fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		fr.setSize((int)(java.awt.Toolkit.getDefaultToolkit().getScreenSize().getWidth()*0.7), (int)(java.awt.Toolkit.getDefaultToolkit().getScreenSize().getHeight()*0.7));
		fr.setLocationRelativeTo(null);
		final ZeichenTest t1 = new ZeichenTest(5, 5);
		fr.add(t1);
		fr.setVisible(true);
		
		 new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					t1.nextRenderStep();
				}
			}
		}).start();
	}

}
```

Gruß Vanny


----------



## rix (3. Nov 2012)

Das würde jetzt aber auf einen Mausklick nicht reagieren, oder?


----------



## vanny (3. Nov 2012)

nein natürlich nicht.
Dafür kannst du dann noch einen MouseListener/MouseMotionListener einbinden plus die nötige Logik.

Das erfüllt vorläufig nur repaint() und thread siehe Titel ^^


----------



## Marco13 (3. Nov 2012)

Es wäre wohl gut, zu wissen, wie das im "echten" Programm aussieht. Wenn du ein Mandelbrot berechnen willst, wirst du das ja kaum IN der paint-Methode machen. Dafür würde es sich anbieten, die ausgerechneten Daten in einem BufferedImage zu speichern (bi.setRGB(x,y,farbe))


----------



## rix (3. Nov 2012)

Bisher läuft die Berechnung in der paint()-Methode, doch. Weshalb ist das eine schlechte Idee? (Und was sollte ich stattdessen machen?)

BufferedImage klingt wie eine gangbare Lösung - ich werds mir ansehen. Wenn Du mir ein Beispiel (oder einen Link auf ein beliebiges Beispiel)  geben, wie man das angeht?


----------



## vanny (3. Nov 2012)

rix hat gesagt.:


> Bisher läuft die Berechnung in der paint()-Methode, doch.



Weshalb ist das eine schlechte Idee? , die Antwort findest du in dem Zitat von dir 
das Zauberwort heisst "Bisher".
Wenn du lauter anderes Zeugs in die paint()-Methode packst, wird diese irgendwann nicht mehr zuverlässig arbeiten.

Zu dem BufferedImage, schon mal HIER nachgeschaut?

Gruß Vanny


----------



## rix (3. Nov 2012)

Ich hatte "bisher" geschrieben, weil impliziert wurde, dass das eine schlechte Idee ist. Das ist ja aber noch kein Grund.

Die einzige Möglichkeit, die Rechenlogik aus der paint()-Methode herauszunehmen, die ich sehe, ist in der Tat ein BufferedImage. Ich werds morgen probieren und mich noch mal melden, wenn ich auch damit mein Ziel nicht erreiche.

Danke auf jeden Fall (auch für den Such-Link; das war definitiv eine dumme Frage meinerseits  )!


----------



## vanny (4. Nov 2012)

rix hat gesagt.:


> ...Das ist ja aber noch kein Grund.



:autsch: Nicht sicher sein zu können, dass deine Komponente richtig zeichnet ist für dich kein Grund?


----------



## rix (4. Nov 2012)

Ich war mir ja noch nicht sicher, dass es wirklich daran lag. 

Dieses spezielle Problem habe ich jedenfalls inzwischen gelöst; danke also für das Mithelfen.


----------



## Marco13 (4. Nov 2012)

Der Hauptgrund, warum das eine schlechte Idee ist, ist, das der Thread, der für das Zeichnen zuständig ist, damit durch die Mandelbrot-Berechnung bockiert wird - und wenn man z.B. die Fenstergröße ändert oder irgendeine Kleinigkeit macht, die ein reines Neuzeichnen auslösen würde (z.B. ein anderes Fenster kurz das Programmfenster verdeckt hat) das komplette Mandelbrot neu berechnet werden muss.


----------



## rix (4. Nov 2012)

Ah, ok. Mir war nicht bewusst, dass das immer ein Neuzeichnen nach sich zieht, danke! Inzwischen ist ja meine Rechenlogik auch vorgelagert, und in paint() wird nur noch das BufferedImage gezeichnet.

Danke noch mal!


----------

