# mehrere repaint() Aufrufe - NUR eine Ausführung. Warum?



## ernst (17. Mai 2007)

Hallo allerseits,
um ein bisschen mehr Durchblick zu bekommen, habe ich etwas mit repaint() experimentiert und zwei zwei Demo-Programme (Versionen) geschrieben, die Kreise auf den Bildschirm zeichnen.
In beiden Programmen wird repaint() mehrmals in einer Schleife aufgerufen.
Ein Aufruf von repaint() zieht einen Aufruf von paintComponent(...) nach sich.

Programm2: 
Jeder Aufruf von repaint() sorgt nur dafür, dass ein paint in die EDT-Warteschlange (EventDispatcher-Thread =  Thread, der die graphische Oberfläche zeichnet und Events herumschickt) gestellt wird.
Ein durch einen alten repaint-Aufruf in die EDT-Warteschlange gestelltes paint wird durch ein neueres (durch einen neuen repaint-Aufruf) in die EDT-Warteschlange gestelltes paint
ersetzt  (ein paint() zieht ein paintComponent(...) nach sich). Man sagt dazu auch "coalescing" (verschmelzen, vereinigen). Mehrere Aufrufe werden zu einem vereinigt.
Das sieht man auch auf dem Bildschirm: es wird nur der letzte Kreise dargestellt!
Dies ist auch klar: Der letzte Kreis ist der aktuellste.
Das ist mir auch alles noch klar.

Aber:
Programm1:
Obwohl repaint() mehrfach aufgerufen wird, wird nur der erste Kreis gezeichnet.
Aber der erste Kreis ist der unaktuellste, der veraltetste Kreis.

Frage1:
Warum wird nicht - wie bei Programm1 - der aktuellste Kreis gezeichnet?

Frage2:
Wenn man das Fenster vergrößert/verkleinert, wird repaint() aufgerufen (von der VJM)
Warum wird aber repaint() nicht (von der VJM) aufgerufen, wenn man das Fenster auf dem Bildschirm verschiebt (bewegt, nicht vergrößert oder verkleinert)?

Frage3:
Wenn man bei Programm1 statt while(k<10) schreibt while(true), bekommt man einen Compilerfehler, da dann die Anweisung f.setVisible(true); nicht mehr erreichbar wird.
Man könnte daher die repaint()-Anweisungen in einen Thread packen (in die Methode run), dann vor der Anweisung 
f.setVisible(true);
diesen Thread starten.
Ist das richtig?

mfg
Ernst 
----------------------------------------------------

```
// Programm1
import java.awt.*;
import javax.swing.*;

public class MainTest7{
	  public static void main(String[] args){
	  	int k;
	  	k = 0;
	    JFrame f = new JFrame();
	    f.setSize(550,550);
	    Diagramm diagramm = new Diagramm(550, 550);
	    f.getContentPane().add(diagramm);
//	    while(true){    	
	    while(k<10){	    	
	      diagramm.repaint();
	      k=k+1;
	    }
	    f.setVisible(true);
	  }
	}

class Diagramm extends JPanel{
  private int xpAnz;
  private int ypAnz;
  private int i,j; 
  private Image myimg;
  private Graphics myg;
  private int sx; 
  private int sy;
  
  public Diagramm(int xpAnz, int ypAnz){  
    i=0; 
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;    
    myimg=null;  
  }
  
  public void paintComponent(Graphics g){
  	if(myimg==null){
  	    sx = this.getSize().width;  
  	    sy = this.getSize().height;
  	    myimg = createImage(sx, sy);
  	    myg = myimg.getGraphics();
  	}
  	myg.setColor(Color.red);
 	myg.drawOval(i , i, 20, 20);
 	i=i+20;
	System.out.println("i="+i);
    synchronized(myimg){
    	g.drawImage(myimg,0,0,null);
    }
  }
}
```
--------------------------------------

```
// Programm2
import java.awt.*;
import javax.swing.*;

public class MainTest8 {
	  public static void main(String[] args){
	    JFrame f = new JFrame();
	    f.setSize(550,550);
	    Diagramm diagramm = new Diagramm(550, 550);
	    f.getContentPane().add(diagramm);
	    Thread t = new Thread(diagramm);
	    t.start();
	    f.setVisible(true);
	  }
	}

class Diagramm extends JPanel implements Runnable{
  private int xpAnz;
  private int ypAnz;
  private int i,k; 
  private Image myimg;
  private Graphics myg;
  private int sx; 
  private int sy;

  public Diagramm(int xpAnz, int ypAnz){  
    i=0; 
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;    
    myimg=null;  
  }
  
  public void paintComponent(Graphics g){
  	if(myimg==null){
  	    sx = this.getSize().width;  
  	    sy = this.getSize().height;
  	    myimg = createImage(sx, sy);
  	    myg = myimg.getGraphics();
  	}
  	myg.setColor(Color.red);
 	myg.drawOval(i , i, 20, 20);
  	g.drawImage(myimg,0,0,null);
  }
	
  public void run(){
  	k = 0;
  	i=11;
//    while(true){    	
    while(k<10){    	
      this.repaint();
      try{
      	//Thread.sleep(500);
      }
      catch(Exception e){}
      i = i+20;
      k = k+1;
    }
  }
}
```


----------



## SlaterB (18. Mai 2007)

> Frage1:
wie willst du überhaupt feststellen, dass nicht der aktuellste Kreis gezeichnet wird? 
anders als in Programm 2 erhöhst du ja das i nicht mehr in der Schleife, sondern nur im Paint,
das erste Paint fängt also auf jeden Fall mit 0 an, 
egal ob es wirklich der erste paint-Aufruf ist oder der zehnte kombinierte,
wenn du die Bedingungen anpasst, wirst du die gleichen Ergebnisse erhalten

dass in beiden Programmen nur einmal paint ausgeführt wird,
hat hier übrigens nichts mit "coalescing" zu tun, behaupte ich mal,
denn alle paint vor setVisible(true) sind sinnlos,
es wird genau einmal wegen setVisible(true) gepainted und gut is


interessanter wirds, wenn du Thread + Schleife nach setVisible(true) setzt, 
dann habe ich bei beiden Programmen in etwa das gleiche Verhalten,

neben einem Kreis werden machmal auch zwei oder gar alle 10 angezeigt,
ist nicht wirklich deterministisch

-----

Frage 2: 
(nur Vermutung)
technisch ist ein Neuzeichnen nicht nötig, das vorhande Bild muss eh vorgehalten werden 
(um bei Mausbewegungen nicht übermalt zu werden)

das Neuzeichnen ist dann eher eine Chance für das Programm, sich zu verändern,
wann man das tut ist Ermessens-/ Einstellungssache,
bei Größenänderung kommt man wohl kaum drumherum,
bei Bewegung sieht es die Engine nicht vor,

ein ähnlicher Grenzfall ist vielleicht die vollständige Überlagerung von anderen Fenstern/ Minimierung,
ich meine, dass dort nach Widerherstellung auch ein repaint gemacht wird,
vielleicht weil sich in diesem Fall nicht lohnt, das alte Bild zwischenzuspeichern

---------

Frage 3:
richtig ja


----------



## Wildcard (18. Mai 2007)

> ein ähnlicher Grenzfall ist vielleicht die vollständige Überlagerung von anderen Fenstern/ Minimierung,
> ich meine, dass dort nach Widerherstellung auch ein repaint gemacht wird,
> vielleicht weil sich in diesem Fall nicht lohnt, das alte Bild zwischenzuspeichern


Meines wissens werden hier volatile Images verwendet. 
Das Bild wird also sofern vorhanden aus dem Speicher der Grafikkarte auf den Screen kopiert.
Bewegt sich ein anderes Fenster in diesen Bereich ist das volatile Image zerstört und es muss neu gezeichnet werden.
Mit dem Mauszeiger verhältet es sich meines Wissens anders, da sorgt das OS dafür das der Überdeckte Bereich neu gezeichnet wird.


----------



## ernst (18. Mai 2007)

SlaterB hat gesagt.:
			
		

> > Frage1:
> 1)
> >wie willst du überhaupt feststellen, dass nicht der aktuellste Kreis gezeichnet wird?
> >anders als in Programm 2 erhöhst du ja das i nicht mehr in der Schleife,
> ...


----------



## SlaterB (18. Mai 2007)

> jedes repaint() in der Schleife (die 10 mal durchlaufen wird) 
> löst ein paintComponent(...) aus, also eine Folge von: 
> paintComponent1(...) ---> i = 0 
> paintComponent2(...) ---> i = 20 
> ... 
> paintComponent10(...) ---> i = 200 

ist das deine Vermutung oder ein Test?
ich sage, dass es nicht so ist..

> Das widerspricht der Bildschirmausgabe (dort wird der erste Kreis gezeichnet). 
> Warum? 
die Bildschirmausgabe ist korrekt, weil eben nur ein paint ausgeführt wird..



---------

> wenn "alle paint vor setVisible(true) sinnlos sind", warum wird dann überhaupt ein Kreis gezeichnet 
> Was passiert da und vor allem welches (zu welchem repaint gehörigen) paint (in der Schleife wird ja 10 mal repaint augferufen) wird aufgerufen? 

wenn man setVisible(true) ausführt, muss eine GUI gezeichnet werden, also wird ein paint durchgeführt

---------

> Das stimmt nicht. In dem Programm oben bei 2) habe ich setVisible(true) immer noch am Ende von main gesetzt und es funktioniert genaus wie bei Programm2 in meinem letzten posting. 

das glaube ich gerne, weil das ganze sehr nicht-deterministisch abläuft
und vielleicht auf meinem Uralt-Rechner anders war,

dazu gebe ich auch keine genauen Aussagen ab


----------



## ernst (18. Mai 2007)

SlaterB hat gesagt.:
			
		

> > jedes repaint() in der Schleife (die 10 mal durchlaufen wird)
> >> löst ein paintComponent(...) aus, also eine Folge von:
> >> paintComponent1(...) ---> i = 0
> >> paintComponent2(...) ---> i = 20
> ...


----------



## SlaterB (18. Mai 2007)

> _Welches_ paint (von den zu den repaint - Aufrufen) wird aufgerufen? 
> Das erste oder das letzte, oder welches? Ich verstehe das System nicht, nach dem dort vorgegangen wird. 

keines, da wie gesagt alle vor setVisible(true) sinnlos sind,

> welches? 

das von  setVisible(true), das erzeugt einen eigenen Aufruf intern

> welches? 

s.o.

-------

> Also: 
> prinzipiell so machen: [..]
> Bist du damit einverstanden? 

ich weiß gar nicht was du bezweckst noch habe ich Kritik daran geübt,
die beiden Varianten können unterschiedliches bewirken, soviel vages steht mal fest! 

ich kann mir aber gut vorstellen, dass auch bei der Variante mit dem paint nach dem setVisible(true) 
noch so manches unerwartetes passieren kann, die GUI-Anzeige vielleicht verzögert erfolgt oder danach noch etwas träge zum Start ist 

wenn du eine ganz ausgeglichene Situation haben willst,
warte vielleicht noch 2-5 Sekunden, also die Aktion erst, nachdem du die GUI schon siehst,
nicht alles in den 100 ms des Starts der GUI

aber das sibd wieder reine Mutmaßungen


----------



## ernst (18. Mai 2007)

>>
>> Das erste oder das letzte, oder welches? Ich verstehe das System nicht, nach dem dort vorgegangen wird. 
>keines, da wie gesagt alle vor setVisible(true) sinnlos sind,
>> welches? 
>das von  setVisible(true), das erzeugt einen eigenen Aufruf intern
>
Da alle repaint vor setVisible(true) sinnlos sind, d.h. nicht ausgeführt werden, muss setVisible(true) (erzeugt einen eigenen Aufruf intern) das paintComponent(...) das erste Mal aufrufen, d.h. mit i=0.
Ist das richtig?

>> Also: 
>> prinzipiell so machen: [..]
>> Bist du damit einverstanden? 
>
>ich weiß gar nicht was du bezweckst 
>
ich will nur wissen, ob ich setVisible(true) _nach_ oder _vor_ repaint() bringen muss.
Ich vermute nach setVisible(true).
Ist das richtig?

mfg
Ernst


----------



## SlaterB (18. Mai 2007)

> muss setVisible(true) (erzeugt einen eigenen Aufruf intern) das paintComponent(...) das erste Mal aufrufen, d.h. mit i=0. 
> Ist das richtig? 

richtig 

> ich will nur wissen, ob ich setVisible(true) _nach_ oder _vor_ repaint() bringen muss. 

du musst keins von beiden, beides ist möglich, 
welches hängt davon ab, was du bezwecken willst,

> Ich vermute nach setVisible(true). 
> Ist das richtig? 

du meinst repaint() nach  setVisible(true)? ja das macht irgenwas, kann Auswirkungen haben,
repaint() vor setVisible(true) dagegen nicht
(habe ich das schonmal erwähnt?  )

und ich wiederhole jetzt nur ständig meine Ausgangsbeobachtung/ Vermutung,
Gewissheit bringen nur Tests,
baue z.B. ein System.out.println in die paint-Operation ein,
mache die repaint-Schleife, warte 5 Sekunden und dann setVisible(true),
wann erscheinen wieviele Meldungen?


----------



## ernst (18. Mai 2007)

1)
>> ich will nur wissen, ob ich setVisible(true) _nach_ oder _vor_ repaint() bringen muss. 
>du musst keins von beiden, beides ist möglich, 
>welches hängt davon ab, was du bezwecken willst,
>
Welchen Sinn kann ein setVisible(true) _nach_  repaint() haben, wenn dadurch die repaint() vor setVisible(true) nicht ausgeführt werden, weil wie du ja selbst schreibst, gilt: "denn alle paint vor setVisible(true) sind sinnlos" 
>

2)
>und ich wiederhole jetzt nur ständig meine Ausgangsbeobachtung/ Vermutung,
>Gewissheit bringen nur Tests,
>baue z.B. ein System.out.println in die paint-Operation ein,
>mache die repaint-Schleife, warte 5 Sekunden und dann setVisible(true),
>wann erscheinen wieviele Meldungen?
>
Mein Programm (nach deinen Anleitungen):

```
import java.awt.*;
import javax.swing.*;

public class MainTest8 {
	  public static void main(String[] args){
	    JFrame f = new JFrame();
	    f.setSize(550,550);
	    Diagramm diagramm = new Diagramm(550, 550);
	    f.getContentPane().add(diagramm);
	    //f.setVisible(true);	    
	    Thread t = new Thread(diagramm);
	    t.start();
	    try{
	    	Thread.sleep(5000);
	    }
	    catch(Exception e){
	    }
	    f.setVisible(true);
	  }
	}

class Diagramm extends JPanel implements Runnable{
  private int xpAnz;
  private int ypAnz;
  private int i,k; 
  private Image myimg;
  private Graphics myg;
  private int sx; 
  private int sy;

  public Diagramm(int xpAnz, int ypAnz){  
    i=0; 
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;    
    myimg=null;  
  }
  
  public void paintComponent(Graphics g){
  	if(myimg==null){
  	    sx = this.getSize().width;  
  	    sy = this.getSize().height;
  	    myimg = createImage(sx, sy);
  	    myg = myimg.getGraphics();
  	}
  	myg.setColor(Color.red);
 	myg.drawOval(i , i, 20, 20);
 	System.out.println("i in paintComponent="+i);
  	g.drawImage(myimg,0,0,null);
  }

  
  public void run(){
  	k = 0;
  	i=11;
//    while(true){    	
    while(k<10){    	
      this.repaint();
      try{
      	//Thread.sleep(500);
      }
      catch(Exception e){}
      i = i+20;
      k = k+1;
    }
  }
}
```
Nach 5 Sekunden gibt dasProgramm für i den Wert 211 aus und der Kreis wird auf dem Bildschirm gezeichnet.
Allerdings verstehe ich nicht den Sinn des Programms:
Die repaint() vor setVisible(true) werden ja alle _nicht_ ausgeführt (was soll das Programm dann für einen Sinn haben?) Am Ende des Programms hat i den Wert 211 und setVisible(true) veranlasst, dass repaint() und damit implizit paintComponent(...) ausgeführt wird, also der Wert für  i, also 211 auf dem Bildschirm ausgegeben wird.

3)
>> als letzter Befehl in main()?
>schon mal gar nicht schlecht, allein schon der Ordnung halber am besten 
>im Bereich von f.setSize(550,550); und VOR f.setVisible(true)
>
>setVisible(true) ist zumindest bei mir immer der Abschluss,
>da wird das Frame auf die Welt losgelassen und muss nicht mehr duch 
>unnötig spät plazierte Kommandos genervt werden
>
Warum ist setVisible(true) bei dir immer der Abschluss, wenn gilt:
"denn alle paint vor setVisible(true) sind sinnlos" ?

mfg
Ernst


----------



## SlaterB (18. Mai 2007)

> Welchen Sinn kann ein setVisible(true) _nach_ repaint() haben, wenn dadurch die repaint() vor setVisible(true) nicht ausgeführt werden, weil wie du ja selbst schreibst, gilt: "denn alle paint vor setVisible(true) sind sinnlos" 

keinen den ich kenne, aber vielleicht fällt dir ja noch einer ein,
wollte ich nicht ausschließen 

------

> Nach 5 Sekunden gibt dasProgramm für i den Wert 211 aus und der Kreis wird auf dem Bildschirm gezeichnet.
> Allerdings verstehe ich nicht den Sinn des Programms: 

wie gesagt: einfach nur ein Test, ob das, was ich sage, überhaupt stimmt, 
scheint der Fall zu sein,

war auch keine direkte Aufforderung, sondern eher ein Hinweis, wie du es prüfen könntest
--------

> Warum ist setVisible(true) bei dir immer der Abschluss, wenn gilt:
> "denn alle paint vor setVisible(true) sind sinnlos" ? 

ich selber würde nie ein paint vor setVisible(true) machen und auch du wirst bald sowas vergessen haben,

daher gibts da überhaupt keinen Zusammenhang, 
'paint vor setVisible(true)' hat nix mit normaler GUI-Programmierung zu tun 

mit Abschluss meine ich, für dich nun extrabreit erklärt, damit du es auch mal verstehst (genervt..):

eine GUI fängt an mit
JFrame f = new JFrame()
dann kommt vielleicht setSize und ähnliche Einstellungen,
das ContentPane wird gefüllt und manch weiteres
(aber auf keinen Fall ein paint-Aufruf  )
irgenwann sind alle Einstellungen fertig,
dann kann die GUI angezeigt werden und 
setVisible(true) ist der letzte Befehl dazu,
der Abschluss der Initialisierun die mit der Erzeugung des JFrames begann..


----------



## ernst (19. Mai 2007)

>wie gesagt: einfach nur ein Test, ob das, was ich sage, überhaupt stimmt, 
>scheint der Fall zu sein,
Ich habe auch nochmals einen Test gemacht mit repaint() _nach_ setVisible(true):


```
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen900{
	public static void main(String[] args){
		int k;
		k = 0;
		JFrame f = new JFrame();
		f.setSize(550,550);
		Diagramm diagramm = new Diagramm(550, 550);
		f.getContentPane().add(diagramm);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
		f.setVisible(true);       
		while(k<10){          
			diagramm.repaint();
			k=k+1;
			System.out.println("k="+k);         
       }
     }
   }

class Diagramm extends JPanel{
  private int xpAnz;
  private int ypAnz;
  private int i,j;
  private Graphics myg;
  private int sx;
  private int sy;
 
  public Diagramm(int xpAnz, int ypAnz){ 
    i=0;
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;   
  }
 
  public void paintComponent(Graphics g){
  	g.setColor(Color.red);
  	g.drawOval(i , i, 20, 20);
  	i=i+20;
  	System.out.println("i="+i);
  }
}
```
Ausgabe:
k=1
k=2
k=3
k=4
k=5
k=6
k=7
k=8
k=9
k=10
i=20
i=40


Problem:
jedes repaint() in der Schleife (die 10 mal durchlaufen wird) löst ein paintComponent(...) aus, also eine Folge von:
paintComponent1(...) ---> i = 0
paintComponent2(...) ---> i = 20
...
paintComponent10(...) ---> i = 200
wobei das erste paintComponent(...) mit i=0 anfängt.
Durch "coalescing" werden die in der EDT-Warteschlange gestellte paintComponent durch das aktuellste paintComponent ersetzt (vereinigt). Das müsste dann aber das letzte sein, also:
paintComponent10(...) ---> i = 200
Das widerspricht der Bildschirmausgabe:
Dort wird als letzter Kreis nicht der Kreis mit i = 200 gezeichnet
Warum? 


mfg
Ernst


----------



## SlaterB (19. Mai 2007)

mann oh meter

> Durch "coalescing" werden die in der EDT-Warteschlange gestellte > paintComponent durch das aktuellste paintComponent ersetzt 
> (vereinigt). Das müsste dann aber das letzte sein,

son Quatsch, es gibt keinen ersten oder letzten,
die Aufrufe werden zu einem vereinigt,
da das i erst im paint erhöht wird, ist bei ersten (vereinten) paint natürlich i=0,
egal obs ein paint war oder hundert paint die zu einem zusammengefasst werden


----------



## ernst (19. Mai 2007)

>son Quatsch, es gibt keinen ersten oder letzten,
>die Aufrufe werden zu einem vereinigt,
>
Das stimmt schon.
Die Frage ist, wie die Vereinigung _konkret_ gemacht wird:
Werden neuere Aufrufe durch ältere ersetzt oder umgekehrt.
Ich habe dir meine Vorstellung geschildert (dass nämlich ältere Aufrufe durch neuere ersetzt werden):
A1)   paintComponent1(...) ---> i = 0
A2)   paintComponent2(...) ---> i = 20
...
A10) paintComponent10(...) ---> i = 200
Bei der Vereinigung von A1 bis A10 kommt also raus:
A1 U A2 U ... U A10 = A10
>
>
>da das i erst im paint erhöht wird, ist bei ersten (vereinten) paint natürlich i=0,
>egal obs ein paint war oder hundert paint die zu einem zusammengefasst werden[/quote]
>
Schildere mir bitte an dem Beispielprogramm mit A1 bis A10 _konkret_ deine Sicht, wie die Vorgehensweise bei der Verschmelzung aussieht.


mfg
Ernst


----------



## Wildcard (19. Mai 2007)

ernst hat gesagt.:
			
		

> Das stimmt schon.
> Die Frage ist, wie die Vereinigung _konkret_ gemacht wird:
> Werden neuere Aufrufe durch ältere ersetzt oder umgekehrt.


Das ist doch *völlig* egal. Ein paint ist ein paint, welche Rolle spielt es da wie alt es ist?  :autsch:


----------



## SlaterB (19. Mai 2007)

das ist so abwegig, das man gar nicht darüber reden kann,
die Operation wird einmal aufgerufen, da sind doch nicht die Effekte von 10 Aufrufen (10x i erhöhen) per Zauberhand mit drin


----------



## ernst (20. Mai 2007)

>>Das stimmt schon.
>>Die Frage ist, wie die Vereinigung _konkret_ gemacht wird:
>>Werden neuere Aufrufe durch ältere ersetzt oder umgekehrt.[/quote]
>Das ist doch *völlig* egal. Ein paint ist ein paint, welche Rolle spielt
> es da wie alt es ist?  
Betrachte mal das folgende Demoprogramm:

```
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen900{
     public static void main(String[] args){
        int k,i;
        i=0;
        k = 0;
       JFrame f = new JFrame();
       f.setSize(550,550);
       Diagramm diagramm = new Diagramm(550, 550);
       f.getContentPane().add(diagramm);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
       f.setVisible(true);       
       while(k<10){
      	System.out.println("i in main="+i);       	
       	diagramm.setI(i);     	
       	diagramm.repaint();
       	i=i+20;
       	k=k+1;
       }
     }
   }

class Diagramm extends JPanel{
  private int xpAnz;
  private int ypAnz;
  private int i;
  private Graphics myg;
  private int sx;
  private int sy;
 
  public Diagramm(int xpAnz, int ypAnz){ 
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;
  }
 
  public void paintComponent(Graphics g){
  	synchronized(this){  	
  		g.setColor(Color.red);
  		g.drawOval(i , i, 20, 20);
  	}
  	System.out.println("i in paintComponent="+i);
  }

  public void setI(int pi){
  	synchronized(this){
  	  	i=pi;  		
  	}
  }
}
```

Einige der in die EDT-Warteschlange gestellten paintComponent(...)
Aufrufe werden vereinigt.
Jeder Aufruf von repaint() bewirkt einen Aufruf von paintComponent() 
In Folgenden wird paintComponent() mit dem Wert von i während des
Aufrufs festgehalten:
paintComponent()  -->   i=0
paintComponent()  -->   i=20
...
paintComponent()  -->   i=180

Es ist doch wohl ein _Unterschied_ ob die obigen paintComponent() zusammengefasst werden
zu dem paintComponent(), wo i den Werz i=0 hat, also zu:
paintComponent()  -->   i=0
oder 
zu dem paintComponent(), wo i den Werz i=180 hat, also zu:
paintComponent()  -->   i=180
Die Kreise werden dann nämlich an verschiedenen Stellen des Bildschirms
ausgegeben.

Bildschirmausgabe:
------------------------------
i in main=0
i in main=20
i in main=40
i in main=60
i in main=80
i in main=100
i in main=120
i in main=140
i in main=160
i in main=180
i in paintComponent=180
i in paintComponent=180
------------------------------

Was mir noch unklar ist:
Warum kommt die Zeile
i in paintComponent=180
i in paintComponent=180
zweimal vor?

mfg
Ernst


----------



## Wildcard (20. Mai 2007)

Du verstehst es offensichtlich noch nicht...
repaint gibt AWT einen Hint das du gerne neu Zeichnen möchtest.
Der EDT legt daraufhin den paint request in die Abarbeitungsqueue.
Nach und nach greift sich der EDT diese requests aus der Queue und führt sie aus.
Es spielt dabei keine Rolle zu welchem Zeitpunk du nun repaint aufgerufen hast, sondern zu welchem Zeitpunkt der EDT den request ausführt.


----------



## SlaterB (20. Mai 2007)

anders ausgedrückt:
eine Bank hat 10000 Euro, bei jedem Überfall kann man nur 1000 Euro klauen,

5 Banden wollen die Bank überfallen, machen sie es einzeln, dann kriegt jeder 1000 und am Ende sind noch 5000 da,

wenn sie sich aber zusammen tun, dann ist das nicht so wie der 5. Überall 
(durch Zauberhand sind schon 4000 weg, nun die fünften 1000)
sondern dann ist das der erste Überfall: 1000 weg, 9000 noch da


----------



## Wildcard (20. Mai 2007)

Was hast du denn geplant?  :shock: 
Krieg ich auch tausend wenn ich mich beim Überfall coalescen lasse?


----------



## ernst (20. Mai 2007)

>Du verstehst es offensichtlich noch nicht...
>
Irgendwo steht mir einer auf der Leitung, bzw. habe ich einen Knoten in meinen Gedanken.
>
repaint gibt AWT einen Hint das du gerne neu Zeichnen möchtest.
>
ok
>
Der EDT legt daraufhin den paint request in die Abarbeitungsqueue.
>
ok
>
Nach und nach greift sich der EDT diese requests aus der Queue und führt sie aus.
>
Das verstehe ich nicht mehr ganz:
Es werden nämlich nicht mehr _alle_ requests durch Swing ausgeführt, sondern durch coalesing ein paar zusammengebastelt (vereinigt).
Angenommen  in der EDT stehen die verschiedenen paints (ich nummeriere sie einfach mal durch):
paint1()
paint2()
...
paintn()

Wie wird nun durch coalesing (vereinigen) aus dieses _vielen_ paints ein paint 
gebastelt?
Diese Frage hast du mir noch nicht beantwortet (bzw. habe ich es nicht mitbekommen oder verstanden).

mfg
Ernst


----------



## Wildcard (20. Mai 2007)

Das entscheidet der EDT. Du sagst 'ich möchte gerne zeichnen' an anderer Stelle rufst du noch 10 mal repaint auf.
Der EDT sieht sich die Sache an und sagt 'da machen wir ein Zeichnen draus' oder eben auch nicht.
Es spielt keine Rolle da wie gesagt der Zeichencode stateless sein muss.


----------



## ernst (21. Mai 2007)

>Das entscheidet der EDT. 
>
ok. das ist mir klar.
>
>Du sagst 'ich möchte gerne zeichnen' an anderer Stelle rufst du noch 10 mal repaint auf.
>Der EDT sieht sich die Sache an und sagt 'da machen wir ein Zeichnen draus' oder eben auch nicht.
>
Er könnte sogar sagen, da machen wir mehrere Zeichnen draus, nicht nur _genau_ ein Zeichnen.
>
Trotzdem wiederhole ich nochmals:
Es werden nämlich nicht mehr _alle_ requests durch Swing ausgeführt, sondern durch coalesing ein paar von Swing bzw. der JVM zusammengebastelt (vereinigt).
Angenommen in der EDT stehen die verschiedenen paints (ich nummeriere sie einfach mal durch):
paint1()
paint2()
...
paintn()

Dass vereinigt wird, hast du ja oben geschrieben. Das ist mir schon klar.
Aber:
_Wie_ wird nun durch coalesing (vereinigen) von Swing bzw. besser der JVM aus dieses _vielen_ paints ein (oder mehrere) paint gebastelt? (werden z.B. oben alle paint durch das letzte, also paintn() ersetzt?)
Diese Frage hast du mir noch nicht beantwortet (bzw. habe ich es nicht mitbekommen oder verstanden).


mfg
Ernst


----------



## SlaterB (21. Mai 2007)

hast du mein Bank-Beispiel nicht gesehen?
stelle dir die einfachste Variante vor die es gibt:
irgendjemand wartet intern x Sekunden (z.B. 0.1) und egal wieviele paint-Aufrufe kommen, genau EIN paint wird ausgeführt,
da kann man gar nicht an Reihenfolge oder erstes/ letztes denken,

hier im Anfängerforum erlebt man ja schon viel, aber sowas ist wirklich extrem,
denk mal über deine Denkweise nach


----------



## schalentier (21. Mai 2007)

Gugg doch in den Sourcecode:


```
class Component...{
  public void repaint(long tm, int x, int y, int width, int height) {
    ...
    Toolkit.getEventQueue().postEvent(e);  
    ...
  }
}

  /**
     * Posts a 1.1-style event to the <code>EventQueue</code>. 
     * If there is an existing event on the queue with the same ID
     * and event source, the source <code>Component</code>'s
     * <code>coalesceEvents</code> method will be called.
     *
     * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
     *		or a subclass of it
     * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
     */
    public void postEvent(AWTEvent theEvent) {
        SunToolkit.flushPendingEvents();
        postEventPrivate(theEvent);
    }


/**
     * Potentially coalesce an event being posted with an existing
     * event.  This method is called by <code>EventQueue.postEvent</code>
     * if an event with the same ID as the event to be posted is found in
     * the queue (both events must have this component as their source).
     * This method either returns a coalesced event which replaces
     * the existing event (and the new event is then discarded), or
     * <code>null</code> to indicate that no combining should be done 
     * (add the second event to the end of the queue).  Either event 
     * parameter may be modified and returned, as the other one is discarded
     * unless <code>null</code> is returned.
     * 


     * This implementation of <code>coalesceEvents</code> coalesces
     * two event types: mouse move (and drag) events,
     * and paint (and update) events.
     * For mouse move events the last event is always returned, causing
     * intermediate moves to be discarded.  For paint events, the new 
     * event is coalesced into a complex <code>RepaintArea</code> in the peer.
     * The new <code>AWTEvent</code> is always returned.  
     *
     * @param  existingEvent  the event already on the <code>EventQueue</code>
     * @param  newEvent       the event being posted to the 
     *          <code>EventQueue</code>
     * @return a coalesced event, or <code>null</code> indicating that no 
     *          coalescing was done
     */
    protected AWTEvent coalesceEvents(AWTEvent existingEvent,
                                      AWTEvent newEvent) {
    ...
          case PaintEvent.PAINT:
          case PaintEvent.UPDATE: {          
              if(peer != null && !(peer instanceof LightweightPeer)) {
                  // EventQueue.postEvent should use peer.coalescePaintEvent
                  return newEvent;
              }
              // This approach to coalescing paint events seems to be 
              // better than any heuristic for unioning rectangles.
              PaintEvent existingPaintEvent = (PaintEvent) existingEvent;
              PaintEvent newPaintEvent = (PaintEvent) newEvent;
              Rectangle existingRect = existingPaintEvent.getUpdateRect();
              Rectangle newRect = newPaintEvent.getUpdateRect();
              
              if (dbg.on) {
                  dbg.println("Component::coalesceEvents : newEvent : nullPeer : x = " + 
                              newRect.x + " y = " + newRect.y + " width = " + newRect.width + 
                              " height = " + newRect.height); 
              }
              
              if (existingRect.contains(newRect)) {
                  return existingEvent;
              }
              if (newRect.contains(existingRect)) {
                  return newEvent;
              }
              
              break;
          }
     ...
   }
```

Wenn schon ein PaintEvent.UPDATE-Event von der gleichen Component in der Queue is, werden die zu zeichnenden Rechtecke irgendwie zusammengepackt. Siehe Code... das hat 5 Minuten gedauert, wo is eigentlich dein Problem?


----------



## ernst (21. Mai 2007)

>Wenn schon ein PaintEvent.UPDATE-Event von der gleichen Component 
>in der Queue is, werden die zu zeichnenden Rechtecke irgendwie 
>zusammengepackt. Siehe Code... das hat 5 Minuten gedauert, 
>wo is eigentlich dein Problem? [/quote]
>
Das "irgendwie zusammengepackt" wird genauer erklärt:

>This method either returns a coalesced event which replaces 
>the existing event (and the new event is then discarded), 
>
also: altes wird ersetzt durch neues. D.h. die zeitliche Reihenfolge wird bei der Vereinigung berücksichtigt.
D.h. bei 10 Events e0, e1, e2, ..., e9
wird durch die Vereinigung der neuste Event:
e0 U e1 U e2 U ...U e9 = e9
>
> or <code>null</code> to indicate that no combining should be done 
> (add the second event to the end of the queue).  
>
oder es wird nicht vereinigt.

mfg
Ernst


----------



## ernst (21. Mai 2007)

>hast du mein Bank-Beispiel nicht gesehen? 
>stelle dir die einfachste Variante vor die es gibt: 
>irgendjemand wartet intern x Sekunden (z.B. 0.1) 
>und egal wieviele paint-Aufrufe kommen, 
>
Diese paint-Aufrufe können z.B. zeitlich nacheinander in einem Array gespeichert werden...
>genau EIN paint wird ausgeführt, 
>
... und dann genau ein paint ausgeführt werden
>
>da kann man gar nicht an Reihenfolge oder erstes/ letztes denken, 
>
Das sehe ich anders. In dem Array ist durch die Indizierung 0,1,2,...
in _natürlicher_ Weise eine "Reihenfolge" definiert und man darf sich schon die Frage stellen, welches ausgeführt wird.
>hier im Anfängerforum erlebt man ja schon viel, 
>aber sowas ist wirklich extrem, 
>denk mal über deine Denkweise nach 
wenn keiner meine Denkweise nachvollziehen kann, ist es wahrscheinlich, dass ich einen schweren Denkfehler in meiner Argumentation habe. Diesen aufzuspüren ist mein Ziel. Leider habe ich es bis jetzt noch nicht geschafft.

mfg
Ernst


----------



## SlaterB (21. Mai 2007)

eine Indizierung wäre ja irrelevant, da sie die Paints nicht unterscheidet,
jeder Paint ist gleich, Zeitpunkt und Anzahl vorheriger Paints sind von Natur aus egal,

ERST wenn du in paint anfängst, Exemplarvariablen zu erhöhen,
würde die Anzahl der Paints eine Bedeutung haben,
aber da gibts immer noch den logischen Finalschuss, dass nur genau ein paint ausgeführt wird


----------



## hupfdule (21. Mai 2007)

ernst hat gesagt.:
			
		

> wenn keiner meine Denkweise nachvollziehen kann, ist es wahrscheinlich, dass ich einen schweren Denkfehler in meiner Argumentation habe. Diesen aufzuspüren ist mein Ziel. Leider habe ich es bis jetzt noch nicht geschafft.



Aber es wurde dir doch jetzt schon so oft gesagt...
Es ist vollkommen irrelevant wie viele paint() Aufrufe ausgeführt werden oder welche. Denn paint() ist zustandslos. Es wird dir nicht garantiert, wann und wie oft es ausgeführt wird. Daher _muss_ die Methode so implementiert werden, dass sie immer wieder das selbe Zeichnen vornimmt (so lange sich die darzustellenden Daten nicht ändern), unabhängig davon, wie oft sie aufgerufen wird.


----------



## schalentier (21. Mai 2007)

hupfdule hat gesagt.:
			
		

> ernst hat gesagt.:
> 
> 
> 
> ...



Jo und das ist die Grundidee vom MVC-Pattern  paint() waere dann ein View und der darf das Model nicht aendern.


----------



## ernst (21. Mai 2007)

>Es ist vollkommen irrelevant wie viele paint() Aufrufe ausgeführt werden oder welche. 
>
das bestreite ich nicht.
>Denn paint() ist zustandslos. Es wird dir nicht garantiert, wann und wie oft es ausgeführt wird. 
>
das bestreite ich auch nicht.
>Daher _muss_ die Methode so implementiert werden, dass sie immer wieder das 
>selbe Zeichnen vornimmt (so lange sich die darzustellenden Daten nicht ändern), 
>unabhängig davon, wie oft sie aufgerufen wird.
>
das bestreite ich auch nicht.

Ich habe nur gefragt, _welches_ paint die JVM aussucht und habe aus den englischen Zitaten von "schalentier" entnommen:
altes wird ersetzt durch neues. D.h. die zeitliche Reihenfolge wird bei der Vereinigung berücksichtigt.
D.h. bei 10 Events e0, e1, e2, ..., e9
wird durch die Vereinigung der neuste Event:
e0 U e1 U e2 U ...U e9 = e9
oder es wird nicht vereinigt. 
Bist du damit einverstanden?


mfg
Ernst


----------



## Wildcard (21. Mai 2007)

> >Es ist vollkommen irrelevant wie viele paint() Aufrufe ausgeführt werden oder welche.
> >
> das bestreite ich nicht.


Wenn du das mittlerweile eingesehen hast, warum fragst du weiter?


----------



## hupfdule (21. Mai 2007)

ernst hat gesagt.:
			
		

> Ich habe nur gefragt, _welches_ paint die JVM aussucht
> und habe aus den englischen Zitaten von "schalentier" entnommen:
> altes wird ersetzt durch neues.



Mag sein. Mag sein, dass das in der letzten Java Version anders war. Mag auch sein, dass es in der nächsten wieder anders ist. Was soll's? Es ist egal. Schließlich bestreitest du ja auch selbst nicht, dass es egal ist.



> D.h. die zeitliche Reihenfolge wird bei der Vereinigung berücksichtigt.
> D.h. bei 10 Events e0, e1, e2, ..., e9
> wird durch die Vereinigung der neuste Event:
> e0 U e1 U e2 U ...U e9 = e9
> ...


Nein. Das ist die Implementierung. Die brauch dich aber nicht zu interessieren. Diese Implementierung kann wieder geändert werden, so das das erste paint() genommen wird. Oder das mittlere. Oder das, was aufgerufen wurde, als die Quersumme der aktuellen Uhrzeit ungerade war. Es ist egal. Es hat keine Relevanz. Die paint() Aufrufe unterscheiden sich nicht.

_Warum_ willst du wissen, wie die Vereinigung passiert? Du selbst akzeptierst, dass es irrelevant ist. Also kann das dein Denkfehler nicht sein.


----------



## ernst (21. Mai 2007)

>eine Indizierung wäre ja irrelevant, da sie die Paints nicht unterscheidet,
>jeder Paint ist gleich, Zeitpunkt und Anzahl vorheriger Paints sind von Natur aus egal,
>
>ERST wenn du in paint anfängst, Exemplarvariablen zu erhöhen,
1)
kannst du mir ein _konkretes_ Beispiel geben, ich kann mir darunter nichts vorstellen.


2)
Schau dir mal den folgenden Quellcode an.
Alle Kreise werden in paintComponent gezeichnet.
Es wird nichts vereint.
Warum verschmelzt (vereinigt) hier die JVM nichts?
Gibt es dazu einen Grund, warum die JVM das so macht.
Ich weiß, die JVM kann vereinigen, oder nicht. Dazu muss sie mich nicht um Erlaubnis fragen.
Mich interessiert aber trotzdem, wie sie das _intern_macht.

3)
Warum wird die Ausgabe doppelt gemacht?
i=20
i=40
i=60
i=80
i=100
i=120
i=140
i=160
i=180
i=200
i=20
i=40
i=60
i=80
i=100
i=120
i=140
i=160
i=180
i=200

Ich vermute weil 
visible(true) auch nochhmals paintComponent() aufruft.
Ist das richtig?



```
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen3{
	public static void main(String[] args){
		int k;
		k = 0;
		JFrame f = new JFrame();
		f.setSize(550,550);
		Diagramm diagramm = new Diagramm(550, 550);
		f.getContentPane().add(diagramm);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
		f.setVisible(true);       
		diagramm.repaint();
	}
}

class Diagramm extends JPanel{
  private int xpAnz;
  private int ypAnz;
  private int i,j;
  private Graphics myg;
  private int sx;
  private int sy;
 
  public Diagramm(int xpAnz, int ypAnz){ 
    i=0;
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;   
  }
 
  public void paintComponent(Graphics g){
  	int i=0;
  	int k=0;
  	g.setColor(Color.red);
  	for(k=0;k<10;k++){
  		g.drawOval(i , i, 20, 20);
  		i=i+20;
  		try{
  		//	Thread.sleep(300);
  		}
  		catch (Exception e){
  		}
  	  	System.out.println("i="+i);  		
  	}
  }
}
```


mfg
Ernst


----------



## SlaterB (21. Mai 2007)

> kannst du mir ein _konkretes_ Beispiel geben, ich kann mir darunter nichts vorstellen

???

DU bist es doch die ganze Zeit, der 
i=i+20;
in paint steht hat, selbst in dem Beispiel was du da postest,

wie kann du nun danach fragen wie man das macht? 
du machst es doch die ganze Zeit: in paint erhöhst du eine Exemplarvariable,
damit machst du dich abhängig von den internen Swing-Vorgängen, was streng zu vermeiden ist

---------

> Ich vermute weil 
> visible(true) auch nochhmals paintComponent() aufruft. 
> Ist das richtig? 

im Grunde richtig, aber bei der Detailebene hier sträflich falsch,

visible(true) ruft NICHT 'nochmals' paint auf, sondern sorgt für den ersten paint-Aufruf,
dahinter steht im Quellcode ein repaint, dieses sorgt anscheinend für den zweiten Aufruf,

wobei man sich natürlich fragen kann, warum diese beiden Aufrufe einzeln abgearbeitet und nicht zu einem zusammengefasst werden 

-----------

> Alle Kreise werden in paintComponent gezeichnet. 
> Es wird nichts vereint. 
> Warum verschmelzt (vereinigt) hier die JVM nichts? 

völlig am Thema vorbei,
Java und Swing verdrehen dir doch nicht den Quellcode,
wenn eine Operation aus 1000 Befehlen besteht, dann werden die Schritt für Schritt abgearbeitet,
wenn einmal paint gestartet ist, kann nichts diese Operation aufhalten, unterbrechen, mit was anderem verschmelzen oder was immer du dir krankes ausmalst,

das einzige, was verschmolzen wird, sind die AUFRUFE, nicht die Operationsausführungen,

und zwar insofern (zum 100. Male), dass 10 Aufrufe genau das bewirken, was ein Aufruf bewirken würde:
eine ganz normale Ausführung von paint, aber eben nur EINE und nicht 10


----------



## ernst (21. Mai 2007)

>du machst es doch die ganze Zeit: in paint erhöhst du eine Exemplarvariable,
>damit machst du dich abhängig von den internen Swing-Vorgängen, was streng zu vermeiden ist
>
warum?
Kannst du mir begründen, warum man das nicht machen soll, bzw. wo das in der Doku steht.

>visible(true) ruft NICHT 'nochmals' paint auf, sondern sorgt für den ersten paint-Aufruf,
>dahinter steht im Quellcode ein repaint, dieses sorgt anscheinend für den zweiten Aufruf,
>
du hast recht.

>> Alle Kreise werden in paintComponent gezeichnet. 
>> Es wird nichts vereint. 
>> Warum verschmelzt (vereinigt) hier die JVM nichts? 
>
>völlig am Thema vorbei,
>Java und Swing verdrehen dir doch nicht den Quellcode,
>wenn eine Operation aus 1000 Befehlen besteht, dann werden die 
>Schritt für Schritt abgearbeitet, wenn einmal paint gestartet ist, 
>kann nichts diese Operation aufhalten, unterbrechen, mit was 
>anderem verschmelzen oder was immer du dir krankes ausmalst,
>das einzige, was verschmolzen wird, sind die AUFRUFE, nicht die Operationsausführungen,
>
du hast recht.


mfg
Ernst


----------



## SlaterB (21. Mai 2007)

> warum? 
> Kannst du mir begründen, warum man das nicht machen soll, bzw. wo das in der Doku steht. 

weil paint-Aufrufe verschmolzen werden, 
weil die Anzahl der Aufrufe nicht vorhersehbar ist/ nicht unbedingt der Anzahl der eigenen Aufrufe entspricht/
auch vom Verhalten des Users (Minimieren/ Maximieren) abhängig ist,
völlig neue Information, was?


----------



## ernst (21. Mai 2007)

>> warum? 
>> Kannst du mir begründen, warum man das nicht machen soll, bzw. wo das in der Doku steht. 
>weil paint-Aufrufe verschmolzen werden, 
>
Damit widersprichst du dir (siehe letztes Posting von dir):
"völlig am Thema vorbei,
Java und Swing verdrehen dir doch nicht den Quellcode,
wenn eine Operation aus 1000 Befehlen besteht, dann werden die Schritt für Schritt abgearbeitet, ..."
>
>weil die Anzahl der Aufrufe nicht vorhersehbar ist/ 
>
Die Anzahl der Aufrufe wird nicht vorhersehbarer, wenn ich diese Anweisungen woanders hinpacke.
>

mfg
Ernst


----------



## SlaterB (21. Mai 2007)

nene, damit zeigst du nur, dass du das letzte Posting nicht verstanden hast,
wenn eine Operation AUSGEFÜHRT wird, dann ist daran nix zu rütteln, dann geht das Schritt für Schritt,

wenn du 100x repaint() aufrufst, dann werden diese Aufrufe auch ausgeführt, nicht vom Compiler wegoptimiert oder sonst wie mysterös umgewandelt,

allerdings bewirken diese nicht viel, sie bewirken nur, dass Swing informiert wird, irgendwann doch bitte mal zu painten,
und dort intern passiert die Magie (wenn auch wahrscheinlich mit ganz normalen Java-Code),
Swing hört sich die 100 Aufrufe an, führt dann aber selber nur einmal paint aus,

vergleiche das nochmal mit einem Schalter an einer Fussgängerampel:
der schaltet maximal alle 30 Sekunden auf Grün, egal, ob man einmal oder 10x draufdrückt,
das Schalter-drücken ist schon bedeutend, hat aber keine direkten Auswirkungen auf die Anzahl der Grünphasen,

genauso ist es irsinnig, sich zu fragen, welches meiner 10 Drücken auf den Schalter letztlich die Grünphase bewirkt,
das hat nix miteinander zu tun außer der einen simplen verständlichen Regel:
'wenn man drückt wirds demnächst grün'

---------

> Die Anzahl der Aufrufe wird nicht vorhersehbarer, wenn ich diese Anweisungen woanders hinpacke. 

selbstverständlich gibt es Alternativen, vielleicht nicht das was du im Sinne hast,
aber zumindest für das Standard-Zeichnen, was ich meinte 

vor einiger Zeit hattest du ja mal Testklassen mit einem Image-Objekt,
das ist ein 100% sicheres Vorgehen, wenn du auf einem Image rummalst, werden die Befehle direkt durchgeführt und nichts und niemand beeinflusst dich da,

male 10x auf einem Bild und 10x repaint (paint zeichnet das Bild),
dann ist es egal, ob durch 10x paint jeder Bildzwischenzustand angezeigt wird (für Millisekunden, eh nicht sichtbar)
oder ob erst ein paint am Ende durchgeführt wird,

du bist ganz frei von paint, dieses hat nichts mit dem Programmzustand zu schaffen sondern gibt einfach den aktuellen Stand aus,

paint kann gar nix falsch machen, es gibt immer simpel den aktuellen Stand aus, egal ob 10x oder 100x pro Sekunde

man könnte sich höchstens über zu lange Zwischenintervalle beschweren, aber das ist ein ganz anderes Problem


----------



## Wildcard (21. Mai 2007)

Da wir uns hier schon ewig im Kreis drehen, merk dir einfach ein paar Grundregeln:
-in paint keine Zustände ändern
-keine Logik in paint
-wenn du (aus welchen Gründen auch immer) mehr Kontrolle brauchst musst du Active Rendering verwenden
-ansonsten: lass AWT die Sache regeln und häng dich nicht an den Implementierungsdetails auf


----------



## ernst (21. Mai 2007)

1)
>nene, damit zeigst du nur, dass du das letzte Posting nicht verstanden hast,
>wenn eine Operation AUSGEFÜHRT wird, dann ist daran nix zu rütteln, 
>dann geht das Schritt für Schritt, 
>
Warum soll man dann nicht in paint i verändern und dort die Kreise ausgeben; es gibt ja - wie du schreibst - keine Vereinigung.
Ich glaube dir und Wildcard natürlich, dass dem so ist, trotzdem würde mich der Grund interessieren.
>

2)
>vergleiche das nochmal mit einem Schalter an einer Fussgängerampel:
>der schaltet maximal alle 30 Sekunden auf Grün, egal, ob man einmal oder 10x draufdrückt,
>das Schalter-drücken ist schon bedeutend, hat aber keine direkten Auswirkungen auf die Anzahl der Grünphasen,
>
Ein schöner, anschaulicher Vergleich.


>> Die Anzahl der Aufrufe wird nicht vorhersehbarer, wenn ich diese Anweisungen woanders hinpacke. 
>selbstverständlich gibt es Alternativen, vielleicht nicht das was du im Sinne hast,
>aber zumindest für das Standard-Zeichnen, was ich meinte 
>vor einiger Zeit hattest du ja mal Testklassen mit einem Image-Objekt,
>
ok

Was mir gerade noch einfällt:
Wildcard hat mal geschrieben:
"Du 'verlierst' nie Bilder (wenn du dein Programm richtig schreibst) weil paint stateless ist. 
Du bildest nur den aktuellen Zustand deiner Daten ab und gehst davon aus das noch nie irgendwas gezeichnet wurde. 
Solange man paint/paintComponent also so verwendet wie es gedacht ist, ist völlig egal wie oft sich AWT dazu entscheidet neu zu zeichnen. Du musst nur wissen das in paint/paintComponent der aktuelle Zustand des Modells visualisiert wird und that's it."

Der Sinn dieser Philosophie ist mir nicht klar, die hinter dieser Idee steckt.
Wenn ich z.B. eine Folge von Zeichnungen zeichnen will, mache ich dies wie folgt
bastele Zeichnung_1 im Arbeitsspeicher zusammen
zeichne sofort Zeichnung_1
...
bastele Zeichnung_n im Arbeitsspeicher zusammen
zeichne sofort Zeichnung_n

Welchen Sinn hat es durch die freundlich Bitte 
"mache doch ein paintComponent, wenn du liebe JVM gerade Zeit und Lusr hast" 
_irgendwann_ einmal eine Zeichnung auf dem Bildschirm zu haben. Bis dahin kann die Zeichnung doch schon veraltet sein. Dieser Sinn ist mir nicht klar.
Normalerweise will man doch sofort zeichnen, oder ?
Du hast dies sehr schön beschrieben mit: "wenn man drückt wirds demnächst grün"
Doch beim  Ablauf eines Programms will man doch nicht warten.
Der Anwender doch erst recht nicht, dem kann es nicht zu schnell gehen.


mfg
Ernst


----------



## SlaterB (21. Mai 2007)

> Warum soll man dann nicht in paint i verändern und dort die Kreise ausgeben; es gibt ja - wie du schreibst - keine Vereinigung. 

INNERHALB der Operation gerne das i um Schleifen zu zählen oder so,
gerne auch Exemplarvariablen auslesen ('male i Kreise')

aber nicht i erhöhen wenn dir der Wert nicht egal ist,
weil es unvorhersehbar ist wann und wieoft der Wert erhöht wird

-----

> Doch beim Ablauf eines Programms will man doch nicht warten. 
> Der Anwender doch erst recht nicht, dem kann es nicht zu schnell gehen. 

warten im übertragenen Sinne, 50 Bilder pro Sekunden reichen jedem,
aber wenn du eine Endlosschleife hast, dann können es auch 5 Mio. Aufrufe pro Sekunde werden, soviel will doch niemand zeichnen,

jedes Zeichnen dauert seine Zeit, vielleicht kann man als Anwendung nicht immer kontrollieren, wie oft man repaint aufruft
(viele GUI-Elemente lösen solche Aufrufe auch aus),
Swing steuert das netterweise,
Swing baut keine Warteampeln ein, sondern verhindert nur unnötig viele Aufrufe,

wenn man natürlich seine Anwendung darauf aufbaut, dass in paint irgendwas hochgezählt wird,
dann hat man in diesem Spezialfall das Nachsehen, aber sowas würde eh nie lange gut gehen

-------

> Wenn ich z.B. eine Folge von Zeichnungen zeichnen will, mache ich dies wie folgt 
> bastele Zeichnung_1 im Arbeitsspeicher zusammen 
> zeichne sofort Zeichnung_1 
> ... 

in normalen Grenzen fallen die Beschränkungen von Swing gar nicht auf,
aber kann natürlich schiefgehen durch das AWT-Prinzip,
da hatte Wildcard doch auch schon oft genug auf Active Rendering oder sowas hinwiesesn


----------



## kleiner_held (21. Mai 2007)

ernst hat gesagt.:
			
		

> Welchen Sinn hat es durch die freundlich Bitte
> "mache doch ein paintComponent, wenn du liebe JVM gerade Zeit und Lusr hast"
> _irgendwann_ einmal eine Zeichnung auf dem Bildschirm zu haben. Bis dahin kann die Zeichnung doch schon veraltet sein. Dieser Sinn ist mir nicht klar.
> Normalerweise will man doch sofort zeichnen, oder ?


Weil die JVM oder genauer gesagt das GUI Toolkit verschiedene Informationen in die Entscheidung einfliessen laesst ob und wann ein Neuzeichenen nötig ist. Wenn dein Fenster mimimiert oder verdeckt oder überhaupt nicht visible ist, dann kann das Toolkit die freundliche Bitte von repaint() ignorieren. Wenn eh nichts sichtbar ist, muss ich auch nichts zeichnen lassen, das steigert die Performance ungemein. Und wenn das Fenster dann (wieder) sichtbar wird, dann sorgt das Toolkit schon dafür, dass alles gezeichnet wird. 
Und in anderen Fällen ruft das Toolkit auch paint() oder paintComponent() auf, wenn kein repaint() von der Komponente kam, weil zum Beispiel der Bildschirmschoner an- und wieder ausging.
Wie schon von anderen Leuten hier oft gesagt, zwischen repaint() und paint() besteht kein deterministischer Zusammenhang. Man muss sich als Entwickler nun mal an die Vorgaben des GUI Frameworks halten Und die lauten bei AWT und SWING das in paint() und paintComponent() NUR gezeichnet wird und nix anderes. Ein i++ kann man auch woanders machen und dann repaint() aufrufen. Das Toolkit sorgt dann dafür, dass keine alten Informationen (beruhend auf dem alten Wert von i) auf dem Bildschirm angezeigt werden, also wenn *nötig* ein paint() aufgerufen wird - aber eben halt nur wenn nötig.


----------



## Wildcard (21. Mai 2007)

ernst hat gesagt.:
			
		

> Welchen Sinn hat es durch die freundlich Bitte
> "mache doch ein paintComponent, wenn du liebe JVM gerade Zeit und Lusr hast"
> _irgendwann_ einmal eine Zeichnung auf dem Bildschirm zu haben. Bis dahin kann die Zeichnung doch schon veraltet sein. Dieser Sinn ist mir nicht klar.
> Normalerweise will man doch sofort zeichnen, oder ?


Hier muss ganz klar ein Schnitt zwischen dem 'neuen Java Far Cry' und einer normalen Desktop Applikation gemacht werden.
Swing und AWT sind *ausschließlich* auf Applikationen ausgelegt, da du in einem Spiel weder Tabellen, noch standard Buttons, noch ScrollPanes brauchst.
Eine Applikation hat einen aktuellen Zustand.
Gezeichnet werden muss, wenn sich entweder dieser Zustand ändert (repaint), oder AWT entscheidet das neu gezeichnet werden muss (Nachricht vom Betriebssystem).
In beiden Fällen ist die Swing/AWT Mechanik goldrichtig, da der Zeitpunkt des Zeichnens unkritisch für die Applikation ist.
Diese Passivität ist aber *nur* im Fenstermodus angebracht und in diesem Kontext auch der richtige Weg.


----------



## ernst (21. Mai 2007)

>> Warum soll man dann nicht in paint i verändern und dort die Kreise ausgeben; 
>>es gibt ja - wie du schreibst - keine Vereinigung. 
>
>INNERHALB der Operation gerne das i um Schleifen zu zählen oder so,
>gerne auch Exemplarvariablen auslesen ('male i Kreise')
>aber nicht i erhöhen wenn dir der Wert nicht egal ist,
>weil es unvorhersehbar ist wann und wieoft der Wert erhöht wird
>
Warum soll ich es aber im folgenden Programmteil nicht machen,
warum gilt dort für i:
"weil es unvorhersehbar ist wann und wieoft der Wert erhöht wird"
die Schleife wird doch dort exakt 10 mal durchlaufen.


```
public void paintComponent(Graphics g){
  	int i=0;
  	int k=0;
  	g.setColor(Color.red);
  	for(k=0;k<10;k++){
  		g.drawOval(i , i, 20, 20);
  		i=i+20;
  		try{
  		//	Thread.sleep(300);
  		}
  		catch (Exception e){
  		}
  	  	System.out.println("i="+i);
```

>jedes Zeichnen dauert seine Zeit, 
>vielleicht kann man als Anwendung nicht immer kontrollieren, wie oft man repaint aufruft
>(viele GUI-Elemente lösen solche Aufrufe auch aus),
>Swing steuert das netterweise,
>
ok, das stimmt. Das hatte ich nicht bedacht.

>Swing baut keine Warteampeln ein, sondern verhindert nur unnötig viele Aufrufe,
>
Das hatte ich nicht bedacht.
>
> Wenn ich z.B. eine Folge von Zeichnungen zeichnen will, mache ich dies wie folgt 
> bastele Zeichnung_1 im Arbeitsspeicher zusammen 
> zeichne sofort Zeichnung_1 
> ... 
>
>in normalen Grenzen fallen die Beschränkungen von Swing gar nicht auf,
>aber kann natürlich schiefgehen durch das AWT-Prinzip,
>da hatte Wildcard doch auch schon oft genug auf 
>Active Rendering oder sowas hinwiesesn[/quote]
>
Klar, ich dachte nur:
Warum passive rendering verwenden, wenn es active rendering gibt?

mfg
Ernst


----------



## Wildcard (21. Mai 2007)

ernst hat gesagt.:
			
		

> Warum passive rendering verwenden, wenn es active rendering gibt?


Sehr einfach zu beantworten:
Davon abgesehen das es deutlich aufwendiger zu implementieren ist, 
möchtest du wirklich das jedes Programm das du im Hintergrund minimiert hast konstant deine CPU belastet weil auf Verdacht gezeichnet wird?


----------



## SlaterB (21. Mai 2007)

ernst hat gesagt.:
			
		

> >> Warum soll man dann nicht in paint i verändern und dort die Kreise ausgeben;
> >>es gibt ja - wie du schreibst - keine Vereinigung.
> >
> >INNERHALB der Operation gerne das i um Schleifen zu zählen oder so,
> ...


tja, was soll man dazu sagen, ich kann sprachlich nur meinen Satz wiederholen 
und dich ermutigen, das ganze doch zu verstehen 

INNERHALB der Operation gerne das i um Schleifen zu zählen oder so,
........

INNERHALB eines paints geht alles, nur über mehrere paints kann man i nicht kontrollieren


----------



## ernst (21. Mai 2007)

>tja, was soll man dazu sagen, ich kann sprachlich nur meinen Satz wiederholen 
>und dich ermutigen, das ganze doch zu verstehen 
>INNERHALB der Operation gerne das i um Schleifen zu zählen oder so,
>........
>INNERHALB eines paints geht alles, nur über mehrere paints kann man i nicht kontrollieren[/quote]
>
1)
Ich verstehe aber immer noch nicht, warum
"es unvorhersehbar ist wann und wieoft der Wert erhöht wird"

2)

```
...
public void paintComponent(Graphics g){
	int i=0;
	int k=0;
  	g.setColor(Color.red);
  	for(k=0;k<10;k++){
  		g.drawOval(i , i, 20, 20);
  		i=i+20;
  		try{
  			Thread.sleep(300);
  		}
  		catch (Exception e){
  		}
  	  	System.out.println("i="+i);  		
  	}
  }
...
```

a)
Da in dem obigen Programmausschnitt gerade _nicht_ vereinigt wird, kommt das Gewünschte auf den Bildschirm 

b)
Allerdings:
Nicht bei _jedem_ Durchgang durch die Schleife wird sleep(300), also 300 ms gewartet.
Sondern es wird zuerst auf einmal, also auf einen Schlag insgesamt 10 * 300 ms gewartet und dann auf einmal die 10 Kreise auf dem Bildschirm ausgegeben. 
Warum?


mfg
Ernst


----------



## ernst (21. Mai 2007)

>möchtest du wirklich das jedes Programm das du im Hintergrund minimiert 
>hast konstant deine CPU belastet weil auf Verdacht gezeichnet wird?
>
Nein nicht jedes, sondern jedes, das der Programmierer zu jedem von ihm gewünschten Zeitpunkt will.

mfg
Ernst


----------



## SlaterB (21. Mai 2007)

> Ich verstehe aber immer noch nicht, warum
> "es unvorhersehbar ist wann und wieoft der Wert erhöht wird" 

paint-Aufrufe können doch zusammengefasst werden,
daher ist bei 10x repaint nicht ersichtlich, ob i nun 10x oder nur 1x erhöht wird,

kannst du mal bitte erklären, wieso du auf Seite 4 so einen simplen Zusammenhang,
der schon auf Seite 1 oder in vorherigen Threads kar sein sollte,
mal wieder NICHT erkennst?

mir reicht das nun, viel Spass weiterhin


----------



## Wildcard (21. Mai 2007)

ernst hat gesagt.:
			
		

> Nein nicht jedes, sondern jedes, das der Programmierer zu jedem von ihm gewünschten Zeitpunkt will.


Was soll der Satz den bedeuten?  :autsch:


----------



## ernst (21. Mai 2007)

>paint-Aufrufe können doch zusammengefasst werden,
>daher ist bei 10x repaint nicht ersichtlich, ob i nun 10x oder nur 1x erhöht wird,
>
in meiner paintComponent() Funktion wird i zuerst mal auf 0 gesetzt.
Das heißt der Endwert von i ist immer gleichgroß, egal ob man paintComponent() 10 mal oder nur 1 mal aufgerufen hat.

mfg
Ernst


----------



## ernst (21. Mai 2007)

>>Nein nicht jedes, sondern jedes, das der Programmierer zu jedem von ihm gewünschten Zeitpunkt will.
>Was soll der Satz den bedeuten?  
>
Es soll die Vorteile von active und passive renderig vereinigen:
Wenn der Programmierer in einer Schleife mehrfach zeichnen will, dann wird das nur dann auch jweils _sofort_ gemacht (also nicht nur ein Bitte wie beim passive renderig), wenn das Fenster sichtbar ist. 
Wenn das Fenster nicht sichtbar ist (z.B. verdeckt) wird nicht gezeichnet.
Wenn das Fenster unsichtbar ist, wird die CPU also nicht belastet.

mfg
Ernst


----------



## Wildcard (21. Mai 2007)

ernst hat gesagt.:
			
		

> Es soll die Vorteile von active und passive renderig vereinigen:


 :lol: 
Wie konnte ich nur so ignorant sein nicht von Anfang an zu erkennen das du das Zeichensystem revolutionieren wirst und die Fehler der Stümper bei SUN korrigieren wirst.

Du glaubst offensichtlich sowieso nur was du auch glauben möchtest, also viel Erfolg bei deinen Vorhaben und mir bleibt immerhin der Trost keines deiner Programme verwenden zu müssen.

Weil's gerade so schön lustig ist beantworte mir doch noch ein paar Fragen bevor du an's Coden gehst:

1. was sind denn die Nachteile von passive Rendering die du meinst korrigieren zu müssen?
2. wofür meinst du das zu brauchen?
3. wie stellst du dir die Implementierung vor?
4. wie willst du erkennen ob ein Fenster verdeckt ist?


----------



## SlaterB (21. Mai 2007)

ernst hat gesagt.:
			
		

> >paint-Aufrufe können doch zusammengefasst werden,
> >daher ist bei 10x repaint nicht ersichtlich, ob i nun 10x oder nur 1x erhöht wird,
> >
> in meiner paintComponent() Funktion wird i zuerst mal auf 0 gesetzt.
> Das heißt der Endwert von i ist immer gleichgroß, egal ob man paintComponent() 10 mal oder nur 1 mal aufgerufen hat.


ok. ich hatte noch deine alten Versionen im Kopft, 

aber angesichst meiner wiederholten Aussage
'INNERHALB der Operation gerne das i um Schleifen zu zählen oder so, '
macht da eine Frage von dir genausowenig Sinn, nur auf eine andere Weise


----------



## ernst (22. Mai 2007)

1)
>Wie konnte ich nur so ignorant sein nicht von Anfang an zu erkennen das du das 
>Zeichensystem revolutionieren wirst und die Fehler der Stümper bei SUN korrigieren wirst.
>
ich bin nicht größenwahnsinig. Es war eine Idee. Die kann auch schlecht sein.
>
>1. was sind denn die Nachteile von passive Rendering die du meinst korrigieren zu müssen?
Ich zitiere dich:
"wenn du (aus welchen Gründen auch immer) mehr Kontrolle brauchst musst du Active Rendering verwenden "
>2. wofür meinst du das zu brauchen?
siehe 1)
>3. wie stellst du dir die Implementierung vor?
Dazu fehlen mir die Kenntnisse
>
>4. wie willst du erkennen ob ein Fenster verdeckt ist?
Genauso wie beim passive rendering
>
2)
Du hast mal geschrieben:
"-in paint keine Zustände ändern 
-keine Logik in paint 
-wenn du (aus welchen Gründen auch immer) mehr Kontrolle brauchst musst du Active Rendering verwenden 
-ansonsten: lass AWT die Sache regeln und häng dich nicht an den Implementierungsdetails auf"

Gibt es sonst noch welche Regeln (bzw. gibt es eine Liste aller Regeln), bzw. gibt es eine Stelle in der Doku, wo diese ganze Regeln stehen, oder sind die auf mehrere Stellen (wo?) verteilt?
Die braucht man dann nur anwenden und die Sache hat sich erledigt.


mfg
Ernst


----------



## kleiner_held (22. Mai 2007)

Zu den Regeln/Eigenschaften von paint() verweise ich mal auf den Orginalartikel von Sun:
Painting in AWT and Swing
Oder auf mehrere Artikel hier in der Forums FAQ.


----------



## Wildcard (22. Mai 2007)

> >1. was sind denn die Nachteile von passive Rendering die du meinst korrigieren zu müssen?
> Ich zitiere dich:
> "wenn du (aus welchen Gründen auch immer) mehr Kontrolle brauchst musst du Active Rendering verwenden "


Das ist nicht per Se ein Nachteil. Im gegenteil, es Erleichtert die Arbeit. Welchen Grund hast du also das Verhalten genauer kontrollieren zu wollen?



> >4. wie willst du erkennen ob ein Fenster verdeckt ist?
> Genauso wie beim passive rendering


Irrtum. AWT erhält die Notification vom Betriebssystem wenn neu gezeichnet werden muss. Diese Events bekommst du aber nicht.


----------



## ernst (22. Mai 2007)

Zu den Regeln/Eigenschaften von paint() verweise ich mal auf den Orginalartikel von Sun:
Painting in AWT and Swing

1)
Ich habe keine Regel entdeckt, die folgendes verbietet:
-in paint keine Zustände ändern
-keine Logik in paint

Es gibt sogar ein Beispiel, wo in paint einiges gerechnet wird:

```
public void paint(Graphics g) {
        // Dynamically calculate size information
        Dimension size = getSize();
        // diameter
        int d = Math.min(size.width, size.height); 
        int x = (size.width - d)/2;
        int y = (size.height - d)/2;

        // draw circle (color already set to foreground)
        g.fillOval(x, y, d, d);
        g.setColor(Color.black);
        g.drawOval(x, y, d, d);
    }
```

2) Ich habe in dem Artikel folgendes nicht ganz kapiert:
Bei Swing steht:
...
"This means that for Swing components, update() is never invoked"
...

Bei Lightweights & System-triggered Painting steht:
"The system-triggered paint request originates from the lightweight framework (i.e., the lightweight is resized), which results in a call to update(), which by default is forwarded to paint() ."

Swing besteht doch aus lightweight Komponenten, aber bei Swing gibt es kein update.
Das ist für mich ein Widerspruch.

mfg
Ernst


----------



## Wildcard (22. Mai 2007)

> Ich habe keine Regel entdeckt, die folgendes verbietet:
> -in paint keine Zustände ändern
> -keine Logik in paint


Es ist ja auch nicht verboten, nur die meisten möchten gerne Programme schreiben die am Schluß auch funktionieren.



> Es gibt sogar ein Beispiel, wo in paint einiges gerechnet wird:


Das bißchen rumrechnen ist natürlich ok, darum geht es gar nicht. Der Code ist nur dazu da die Daten korrekt visuell zu repräsentieren. Du wirst aber feststellen das kein Member verändert wird.


----------

