repaint(), EDT-Warteschlange und Threads

Status
Nicht offen für weitere Antworten.

ernst

Top Contributor
Hallo allerseits,
um mehrfach hintereinander z.B. Kreise auf dem Bildschirm auszugeben, genügt es nicht, in einer Schleife immer wieder repaint aufzurufen.
Grund:
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 z.B. auch auf dem Bildschirm: es wird nur der letzte Kreise dargestellt, weil er der aktuellste ist.
So weit ist mir das alles noch verständlich.
"kleiner Held" hat mir dankenswerterweise (unten) ein Programm vorgestellt, mit dem man das Problem lösen kann. Dieses Programm benutzt "synchronized", mit dem verhindert werden soll, dass mehrere Threads gleichzeitig auf die Variable myimg zugreifen können.

Frage:
In der EDT-Warteschlange befinden sich (durch mehrere repaint() Aufrufe verursachte) paint (ein paint() zieht ein paintComponent(...) nach sich)) Aufrufe (wobei einige durch "coalescing" vereinigt wurden).
kurz:
paint1()
paint2()
paint3()
....
Das Wort "Warteschlange" in EDT-Warteschlange bedeutet doch, dass die einzelnen paint() _hintereineinander_ ausgeführt werden müssen, aber dann braucht man doch _kein_ synchronized, da dies dann nicht nebenläufig, also _nicht_ parallel erfolgt (und es dann keine Probleme beim Zugriff verschiedener, parallel laufender Threads auf _eine_ Variable gibt).
Oder wo ist da mein Denkfehler?

mfg
Ernst


Code:
package de;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class MainVerzoegertZeichnen4 {
     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;
  private Image myimg;
 

  public Diagramm(int xpAnz, int ypAnz){
    i=0;
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;   
    myimg = new BufferedImage(xpAnz, ypAnz, BufferedImage.TYPE_INT_RGB);
  }
 
  //@Override
/*  
  public Dimension getPreferredSize()
  {
     return new Dimension(xpAnz, ypAnz);
  }
*/ 
 
  protected void paintComponent(Graphics g){
     synchronized(myimg){
        g.drawImage(myimg,0,0,null);
     }
  }
   
  public void addKreis(){
     synchronized(myimg){
        Graphics myg = myimg.getGraphics();
        myg.setColor(Color.red);
        myg.drawOval(i , 2*i+15, 20, 20);
        myg.dispose();
     }
  }

  public void run(){
//    while(i<200){
  	while(true){    	
      try{
        //Thread.sleep(500);
      }
      catch(Exception e){
      }
      i = i+20;
      addKreis();
      this.repaint();
    }
  }
}
 
S

SlaterB

Gast
bei dir greifen nebenläufig der Diagramm-Thread (addKreis()) und paintComponent (drawImage) auf das Bild zu,
deshalb wahrscheinlich das synchronized
 

ernst

Top Contributor
kleiner_held hat gesagt.:
SlaterB hat gesagt.:
bei dir greifen nebenläufig der Diagramm-Thread (addKreis()) und paintComponent (drawImage) auf das Bild zu, deshalb wahrscheinlich das synchronized
>So ist es.
>
1)
Das kann ich nachvollziehen und habe zum Testen gleich das Programm (siehe unten) geschrieben.
Aber warum werden dort nicht
diagramm.setI(i) und diagramm.repaint()
synchronisiert?
Ich habe doch jeweils in
setI(i) und paintComponent mit
synchronized(this) veranlaßt dass nicht gelichzeitig auf das Objkt diagramm zugegriffen werden kann?

2)
warum kann man eigentlich nicht
synchronized(i){
....
}
schreiben, wobei i ein integer ist?
Aber
synchronized(myimg){
....
}
wobei myimg den Datentyp Image hat?


Code:
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen901{
     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.setVisible(true);       
       while(k<10){
       	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;  		
  	}
  	System.out.println("i in setI="+i);  	
  }
}


mfg
Ernst
 
S

SlaterB

Gast
> Aber warum werden dort nicht
> diagramm.setI(i) und diagramm.repaint()
> synchronisiert?

grob betrachtet sieht es für mich so aus, als wenn da synchronisiert wird,
was veranlasst dich denn zu der Vermutung, dass es nicht so ist?

--------

primitive Datentypen wie int sind den Objekten in mancher Weise unterlegen,
z.B. haben sie keinen Monitor für synchronized
 

ernst

Top Contributor
>grob betrachtet sieht es für mich so aus, als wenn da synchronisiert wird,
>was veranlasst dich denn zu der Vermutung, dass es nicht so ist?
>
Die Ausgabe auf der Konsole:
i in setI=0
i in setI=20
i in setI=40
i in setI=60
i in setI=80
i in setI=100
i in setI=120
i in setI=140
i in setI=160
i in setI=180
i in paintComponent=180
i in paintComponent=180
und die auf dem Bildschirm (es wird nur ein Kreis gezeichnet)

>primitive Datentypen wie int sind den Objekten in mancher Weise unterlegen,
>z.B. haben sie keinen Monitor für synchronized
>
Aber beliebige selbstgebastelte Objekte dürfen mit synchroized verwendet werden?

mfg
Ernst
 
S

SlaterB

Gast
ja dürfen,

und das andere liegt doch am Zusammenfassen der paints,
es wird erst am Ende ein paint ausgeführt,

und das Zusammenfassen geschieht auch nicht erst im Laufe des paints, wenn der synchronized-Block schon geöffnet ist,
oder was immer du dir denkst,

erst 10x setI, dann paintComponent, bei dir anscheinend 2x,
unabhängig von synchronized, sonder allein abhängig von der Enscheidung Swings, zu zeichnen oder nicht,

habe deinen Code 1:1 bei mir ausgeführt und unterschiedliche Ergebnisse,
darunter auch:

i in paintComponent=0
i in setI=0
i in paintComponent=0
i in setI=20
i in paintComponent=20
i in setI=40
i in paintComponent=40
i in setI=60
i in paintComponent=60
i in setI=80
i in paintComponent=80
i in setI=100
i in paintComponent=100
i in setI=120
i in paintComponent=120
i in setI=140
i in paintComponent=140
i in setI=160
i in paintComponent=160
i in setI=180
i in paintComponent=180

alles nichtdeterministisch ;)
 

ernst

Top Contributor
>und das andere liegt doch am Zusammenfassen der paints,
>es wird erst am Ende ein paint ausgeführt,
>
>
In der EDT-Warteschlange befinden sich (durch mehrere repaint() verursacht: --> paint() --> paintComponent(...)):
paintComponent1(...)
paintComponent2(...)
paintComponent3(...)
....
Wenn ich das so sehe wie du, ist mir das zwar klar, aber:
Frage:
Warum werden diese paintComponent(...)-Aufrufe bei dem Programm von "kleinerHeld" (Programm: siehe Anfangsposting von mir) nicht genauso vereinigt.
Was hat er _gemacht_, dass diese Vereinigung nicht passiert?

mfg
Ernst
 
S

SlaterB

Gast
man, dass ich ich dich immer alles nachfragen muss,
wenn du Ausgaben hast, dann poste sie doch gleich dazu..

also: wie kommst du darauf, dass dort die Vereinigung nicht passiert?
bei mir passiert sie, wenn ich
System.out.println("i: " + i);
in paint einfüge und die Schleife netterweise nur bis 200 und nicht ins Unendliche laufen lasse,
dann ist die Ausgabe
i: 200

wiederum kommt immer genau eine Ausgabe, wenn die Schleife VOR dem setVisible(true) liegt,
warum dürfte ja inzwischen geklärt sein ;)

startet der Thread erst später, habe ich mal eine Ausgabe, mal mehrere, mal alle,
ganz wie im unteren Programm

--------

und noch ein Tipp:
baue bitte
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
in alle deine Programme ein, besonders wenn da while-true-Threads drin sind, die unendlich weiterlaufen..,

mit diesem Befehl wird das Programm beendet, wenn das Fenster geschlossen wird
 

ernst

Top Contributor
>wenn du Ausgaben hast, dann poste sie doch gleich dazu..
>
da alle Kreise ausgegeben wurden, war ich so überzeugt ...
sorry.
>
>also: wie kommst du darauf, dass dort die Vereinigung nicht passiert?
>bei mir passiert sie, wenn ich
>System.out.println("i: " + i);
>in paint einfüge und die Schleife netterweise nur bis 200 und nicht ins Unendliche laufen lasse,
>dann ist die Ausgabe
>i: 200
>
Du hast recht!!
Da alle Kreise ausgegeben wurden, war ich so überzeugt, dass die Vereinigung nicht gemacht wird.
Deswegen habe ich die Ausgabe von i nicht mehr angeschaut...
Es wird also vereinigt! Ich habe mich getäuscht.

Frage:
Was muss ich aber dann machen, wenn ich _alle_ Bilder (alle paintComponent()-Aufrufe im EDT sollen realisiert werden) haben will, wenn also die Vereinigung verhindert werden soll?



>und noch ein Tipp:
>baue bitte
>f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
als letzter Befehl in main()?

mfg
Ernst
 
S

SlaterB

Gast
> Was muss ich aber dann machen, wenn ich _alle_ Bilder (alle paintComponent()-Aufrufe im EDT sollen realisiert werden) haben will, wenn also die Vereinigung verhindert werden soll?

also ich kenne mich da nicht allzu sehr aus,
aber 1 Mio. repaint pro Sekunde sind sicherlich zu viel ;)
wenn du da auf unter die typischen Frames Per Second von Computerspielen (z.B. 100 pro Sekunde) kommst, sieht es vielleicht besser aus,

andererseits ist es im Bereich von 10ms schwer, genau zu timen.,
also entweder so viel repaint wie es gut passt, und nicht weiter stören, wenn welche wegfallen (würde der Betrachter eh nicht sehen)
oder ordentlich Abstand lassen, bei 1 paint pro Sekunde kann nix schiefgehen ;)

------

> 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 ;)
 

ernst

Top Contributor
>also ich kenne mich da nicht allzu sehr aus,
>aber 1 Mio. repaint pro Sekunde sind sicherlich zu viel ;)
>wenn du da auf unter die typischen Frames Per Second von
>Computerspielen (z.B. 100 pro Sekunde) kommst, sieht es vielleicht besser aus,
>andererseits ist es im Bereich von 10ms schwer, genau zu timen.,
>also entweder so viel repaint wie es gut passt, und nicht weiter stören,
>wenn welche wegfallen (würde der Betrachter eh nicht sehen)
>oder ordentlich Abstand lassen, bei 1 paint pro Sekunde kann nix schiefgehen ;)
>
>
Was hältst du von diesem Vorschlag?
Code:
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen3 {
	  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.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 	    
	    f.setVisible(true);
	  }
	}

class Diagramm extends JPanel implements Runnable{
  private int xpAnz;
  private int ypAnz;
  private int i,j,k; 
  private Image myimg;
  private Graphics myg;
  private int sx; 
  private int sy;
  private boolean ichMaleGerade;
  Object lockForAccessToFlag = new Object();
  
  public Diagramm(int xpAnz, int ypAnz){  
    i=0;
    k=0;
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;    
    myimg=null;
    synchronized(lockForAccessToFlag){
    	ichMaleGerade=true;
    }
  }
  
  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 , j, 20, 20);
    synchronized(lockForAccessToFlag){ 	
    	ichMaleGerade=false;
      	System.out.println("k in paintComponent="+k);    	
  		lockForAccessToFlag.notify();    	
    }
  	g.drawImage(myimg,0,0,null);
  }
	
  public void run(){
  	j=11;
  	i=11;
//    while(true){    	
  	while(k<100){    	
  		System.out.println("k in run="+k);
  		this.repaint();
      synchronized(lockForAccessToFlag){      
	      while(ichMaleGerade==true){
	      	try{
	      		lockForAccessToFlag.wait();
	      	}
	      	catch(Exception e){
	      		System.out.println("Hallo");
	      	}
	      }
	      ichMaleGerade=true;
      }
      try{
      	//Thread.sleep(5);
      }
      catch(Exception e){}
  
      i = i+20;
      if(i>400){
      	j=j+5;
      	i=11;
      }
      if(j>400)
      	j=11;
      k=k+1;
  	}
  }
}


mfg
Ernst
 
S

SlaterB

Gast
ich bin kein Fan von synchronized und co.,
dein ganzes Programm mag ich aber auch gar nicht, da das wohl den PC die ganze Zeit arbeiten lässt,

wenn du aber so viel malen willst mag es so gehen,
kenne mich da aber wirklich nicht aus
 

ernst

Top Contributor
>ich bin kein Fan von synchronized und co.,
>dein ganzes Programm mag ich aber auch gar nicht,
>da das wohl den PC die ganze Zeit arbeiten lässt,
>
du hast recht.
Wenn ich aber mit sleep(...) irgend eine noch so kleine oder große Verzögerung einbaue, brauche ich nicht 100% CPU-Zeit, sondern entsprechend (der Verzögerung von sleep) weniger _und_ habe eine Garantie, dass nicht ein paar painComponent(...) Aufrufe durch "coalescing" vereinigt wurden, und deshalb ein paar Bilder verloren gingen.
>
>wenn du aber so viel malen willst mag es so gehen,
>kenne mich da aber wirklich nicht aus[/quote]
>
ich kenne mich auch nicht aus. Ich probiere eben in ein paar Demoprogrammen ein paar Sachen aus.

mfg
Ernst
 

Wildcard

Top Contributor
Wenn du die Kontrolle darüber brauchst wann und wie oft gezeichnet werden muss, kannst du diesen Weg nicht gehen, daher sehe ich keinen Sinn in deinen Versuchen.
 

ernst

Top Contributor
>Wenn du die Kontrolle darüber brauchst wann und wie oft gezeichnet werden muss,
>kannst du diesen Weg nicht gehen,
>
1) warum kann ich diesen Weg (Programm von mir) nicht gehen (was ist falsch)?
2)zeige mir einen gehbaren Weg, eine Alternative.

mfg
Ernst
 

Wildcard

Top Contributor
Weil AWT entscheidet wann gezeichnet wird und wann nicht. repaint ist nur eine freundliche Bitte. Brauchst du die volle Kontrolle über die Zeichenroutinen musst du zu Active-Rendering greifen.
 

ernst

Top Contributor
>Weil AWT entscheidet wann gezeichnet wird und wann nicht.
>
Bei mir ist das doch Swing, oder ?
>
>repaint ist nur eine freundliche Bitte.
>
Und diese freundliche Bitte gestalte ich mit meinem letzten Programm zu einer vollen Kontrolle (keine Bilder gehen verloren) oder ist das eher eine "Vergewaltigung" von repaint?

>Brauchst du die volle Kontrolle über die Zeichenroutinen musst du zu Active-Rendering greifen.
>
Davon habe ich leider Null Ahnung.
Kannst du mir ein paar Tipps, Links und vielleicht ein einfachstes Programm geben ?

mfg
Ernst
 

Wildcard

Top Contributor
Bei mir ist das doch Swing, oder ?
Swing ist ein Lightweight Toolkit das auf AWT aufsetzt. Im Klartext das 'echte' Zeichnen macht AWT.
Und diese freundliche Bitte gestalte ich mit meinem letzten Programm zu einer vollen Kontrolle
Nein, du kannst weder deterministisch festlegen wann, noch wie oft gezeichnet wird.
Kannst du mir ein paar Tipps, Links und vielleicht ein einfachstes Programm geben ?
http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html
 

ernst

Top Contributor
1)
>>Und diese freundliche Bitte gestalte ich mit meinem letzten Programm zu einer vollen Kontrolle
>Nein, du kannst weder deterministisch festlegen wann, noch wie oft gezeichnet wird.
>
"wann " ist mir klar
"wie oft":
Meinst du, dass man dies nicht wegen des "coalescing" (verschmelzen, vereinigen) - d.h. mehrere Aufrufe werden zu einem vereinigt - machen kann?
>
2)
>http://java.sun.com/docs/books/tutorial/extra/fullscreen/rendering.html
>
Danke, ich werde mir das mal anschauen.

3)
Eine Verständnisfrage habe ich noch:
In den Programmen in meinen letzten Postings habe ich immer eine Variable von Datentyp Image benutzt:
private Image myimg;
mit den zugehörigen Methoden
protected void paintComponent(Graphics g){
synchronized(myimg){
g.drawImage(myimg,0,0,null);
}
System.out.println("i: " + i);
}

public void addKreis(){
synchronized(myimg){
Graphics myg = myimg.getGraphics();
myg.setColor(Color.red);
myg.drawOval(i , 2*i+15, 20, 20);
myg.dispose();
}

4)
Jetzt habe ich mal probiert, dies ohne Image zu machen, sondern nur mit Graphics g:
protected void paintComponent(Graphics g){
g.drawOval(i , 2*i+15, 20, 20);
System.out.println("i: " + i);
}
Code:
package de;
import java.awt.*;
import javax.swing.*;

public class MainTest2 {
     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();
//       f.setVisible(true);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);       
     }
   }

class Diagramm extends JPanel implements Runnable{
  private int xpAnz;
  private int ypAnz;
  private int i;
  private Image myimg;
 

  public Diagramm(int xpAnz, int ypAnz){
    i=0;
    this.xpAnz=xpAnz;
    this.ypAnz=ypAnz;   
  }
 
  protected void paintComponent(Graphics g){
    g.drawOval(i , 2*i+15, 20, 20);
     System.out.println("i: " + i);      
  }


  public void run(){
    while(i<200){
//  	while(true){    	
      try{
       }
      catch(Exception e){
      }
      i = i+20;
      this.repaint();
    }
  }
}

Dann wurde nur noch _ein_ Kreis auf dem Bildschirm ausgegeben.
Meine Erklärung:
a)
Durch "coalescing" werden einige (bei mir: alle bis auf einen) paintComponent-Aufrufe vereinigt.
dadurch werden nicht mehr alle
g.drawOval(i , 2*i+15, 20, 20);
Aufrufe (in paintComponent(...)) ausgeführt und deswegen fehlen die dazugehörigen Bilder auf dem Bildschirm.

b)
Im anderen Programm dagegen werden durch
addKreis()
die ganzen Kreise in das Image myimg gezeichnet.
Wenn dann mal ein Bild wegen "coalescing" auf dem Bildschirm verloren geht, macht das nichts aus, weil das nächste Bild (speziell das letzte Bild alle Kreis enthält) immer einen Kreis mehr enthält als das vorige.
Im schlimmste Fall - wenn nämlich nur das letzte Bild auf dem Bildschirm ausgegeben wird - enthält dieses sämtliche Kreise und der Anwender sieht nicht, dass ein paar Bilder verloren gingen.
Er würde es merken, wenn das nächste Bild einen Kreis weniger als das vorige enthalten würde.
Ist meine Erklärung richtig?
Oder braucht man das Image auch noch aus anderen Gründen (wegen des Flackerns auf dem Bildschirm; habe ich irgendwo mal gelesen), oder stimmt das nicht?

mfg
Ernst
 

Wildcard

Top Contributor
Du hast schon ein ganz grundlegendes Verständnisproblem mit der Art wir Passive-Rendering funktioniert.
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.
 

ernst

Top Contributor
Wildcard hat gesagt.:
Du hast schon ein ganz grundlegendes Verständnisproblem mit der Art wir Passive-Rendering funktioniert.
Du 'verlierst' nie Bilder (wenn du dein Programm richtig schreibst)
Das ist der Punkt...
In dem Programm mit Image wurde das Programm richtig geschrieben (alle Kreise sind in myimg) und in der anderen Version sind in g nicht alle Kreise mehr enthalten und deswegen ist es falsch geschrieben.
Oder siehst du das anderst?
[/quote]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.[/quote]
Und wenn paint nicht stateless sein soll, man also die verschiedenen Zustände auf dem Bildschirm darstellen will, dann braucht man entweder die Notlösung von mir oder den professionellen Vorschlag von dir.

mfg
Ernst
 

Wildcard

Top Contributor
ernst hat gesagt.:
Und wenn paint nicht stateless sein soll, man also die verschiedenen Zustände auf dem Bildschirm darstellen will, dann braucht man entweder die Notlösung von mir oder den professionellen Vorschlag von dir.
Zeichnen sollte immer von der Logik getrennt sein. Das eine hat mit dem anderen nichts zu tun.
Passive Rendering:
Die Anwendung rutscht auf den Daten rum und bildet diese ab wann immer gezeichnet werden soll.

Active Rendering:
Die Anwendung rutscht auf den Daten rum und zeichnet in regelmäßigen Abständen selbst.

In beiden Fällen muss es für das Modell völlig egal sein wie oft nun konkret gerendert wurde.
 

ernst

Top Contributor
>Zeichnen sollte immer von der Logik getrennt sein.
>Das eine hat mit dem anderen nichts zu tun.
>
Okay, das ist OOP (da kenne ich mich nicht so gut aus)

Nochmals zu meiner vorigen Frage (wichtig für mein Verständnis):
...
Oder braucht man das Image auch noch aus anderen Gründen (wegen des Flackerns auf dem Bildschirm; habe ich irgendwo mal gelesen), oder stimmt das nicht?

mfg
Ernst
 

Wildcard

Top Contributor
ernst hat gesagt.:
Oder braucht man das Image auch noch aus anderen Gründen (wegen des Flackerns auf dem Bildschirm; habe ich irgendwo mal gelesen), oder stimmt das nicht?
Um Flackern zu vermeiden besteht eine Möglichkeit in sog. DoubleBuffering. Dabei wird ein Offscreen Image verwendet (meistens ein Compatible- oder VolatileImage) das zum Rendern verwendet wird und das anschließend auf den Bildschirm kopiert wird.
Damit werden sichtbare Artefakte (Flackern) vermieden.

Bleibt man im normalen 'Applikations' Modus, d.h. Passive Rendering, ist dieses Vorgehen nur für AWT von Nöten. Medium Weight Container des Swing Toolkits (JFrame, JDialog, JWindow) verwenden standardmäßig eine BufferStrategy die Flackern verhindert.
 

ernst

Top Contributor
Bei einem Lösungsvorschlag von euch wurde mir geraten, einfach eine Verzögerung zwischen zwei repaints einzubauen.

1)
Im folgenden Programm habe ich das gemacht.
Allerdings habe ich dazu keinen Thread erzeugt, sondern nur mit Thread.sleep(100) verzögert.
100 ms reichen offensichtlich noch nicht aus, um die Ausgabe zu synchronisieren.
(sieht man, wenn man sich die Ausgabe auf dem Bildschirm anschaut)
i in main=20
i=20
i=20
i in main=40
i=40
i=40
i in main=60
i=60
i in main=80
i=80
i in main=100
i=100
i in main=120
i in main=140
i=140
i=140
i in main=160
i=160
i in main=180
i=180
i in main=200

Code:
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen4 {
	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){
	  		try{
	  			Thread.sleep(100);
	  		}
	  		catch(Exception e){}
	  		diagramm.repaint();
	  		k=k+1;
	  		i = i+20;
	      	System.out.println("i in main="+i);	  		
	  		diagramm.setI(i);
       }
	}
} 

class Diagramm extends JPanel{
	  private int xpAnz;
	  private int ypAnz;
	  private int i;
	  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 setI(int pi){
	  	i = pi;
	  }
	  
	  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="+i);
	     synchronized(myimg){
	     	g.drawImage(myimg,0,0,null);
	    }
	  }
}

2)
Im folgenden Programm habe ich einen Thread erzeugt und dann in run mit Thread.sleep(100) verzögert.
100 ms reichen hier offensichtlich auch noch nicht aus, um die Ausgabe zu synchronisieren.
(sieht man, wenn man sich die Ausgabe auf dem Bildschirm anschaut)
i in run=20
i in run=40
i in run=60
i in paintComponent=60
i in paintComponent=60
i in paintComponent=60
i in run=80
i in paintComponent=80
i in run=100
i in paintComponent=100
i in run=120
i in paintComponent=120
i in run=140
i in paintComponent=140
i in run=160
i in paintComponent=160
i in run=180
i in paintComponent=180
i in run=200
i in paintComponent=200

Code:
package de;
import java.awt.*;
import javax.swing.*;

public class MainVerzoegertZeichnen5 {
	  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.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 	    
	    f.setVisible(true);
	  }
	}

class Diagramm extends JPanel implements Runnable{
  private int xpAnz;
  private int ypAnz;
  private int i; 
  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 setI(int pi){
  	i = pi;
  }
*/  
  
  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);
  	System.out.println("i in paintComponent="+i);
  }
	
  public void run(){
  	int k;
  	k=0;
  	i=0;
    while(k<10){
    	k=k+1;
    	i=i+20;
      	System.out.println("i in run="+i);   	
    	this.repaint();
    	try{
    		Thread.sleep(100);
    	}
    	catch(Exception e){}
    }
  }
}


Fragen:
1) Ist es _unbedingt nötig_, einen Thread zu verwenden, bzw. welchen Nachteil hat es, wenn man ihn nicht verwendet oder kann man auf ihn verzichten?

2) Sind nur die 100 ms zu wenig (um alle Zeichnungen auf den Bildschirm zu bringen) oder habe ich einen Denkfehler in meinem Programm ?

mfg
Ernst
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
D Repaint Funktioniert nicht AWT, Swing, JavaFX & SWT 2
D JUNG Repaint function does not work AWT, Swing, JavaFX & SWT 2
E repaint Probleme AWT, Swing, JavaFX & SWT 13
G listener repaint() - verschiedene Darstellung AWT, Swing, JavaFX & SWT 24
ExceptionOfExpectation Textdarstellung auf einem Canvas mit Hilfe von repaint(); AWT, Swing, JavaFX & SWT 6
J actionperformed wird nicht aufgerufen/ repaint() AWT, Swing, JavaFX & SWT 6
L Swing repaint() ruft paintComponent(g1d) nicht auf AWT, Swing, JavaFX & SWT 12
G Repaint wird nicht durchgeführt AWT, Swing, JavaFX & SWT 8
I Swing Verhindern, dass repaint() kaskadiert AWT, Swing, JavaFX & SWT 6
ms_cikar Update swingUtilities Repaint in der Schleife AWT, Swing, JavaFX & SWT 3
T Swing Probleme mit repaint() bzw. JScrollPane AWT, Swing, JavaFX & SWT 7
N Swing JButtons werden nach repaint() doppelt dargestellt AWT, Swing, JavaFX & SWT 12
K Methode repaint() AWT, Swing, JavaFX & SWT 1
B Swing Wann brauche ich repaint() ? AWT, Swing, JavaFX & SWT 1
javampir Swing repaint in JavaFX Anwendung AWT, Swing, JavaFX & SWT 3
A repaint(); AWT, Swing, JavaFX & SWT 9
J Swing ungewünschter Nebeneffekt bei der repaint() Methode AWT, Swing, JavaFX & SWT 3
A Problem: repaint() - Schleife AWT, Swing, JavaFX & SWT 3
S 2D-Grafik repaint()-Aufruf. Und nichts geschieht. AWT, Swing, JavaFX & SWT 5
Joew0815 JDialog repaint() funktioniert nicht wie gewünscht. AWT, Swing, JavaFX & SWT 2
P JPanel und Repaint AWT, Swing, JavaFX & SWT 5
J JavaFX Automatisches Neuzeichnen ("Repaint") abstellen. AWT, Swing, JavaFX & SWT 10
F JTable Repaint Issue AWT, Swing, JavaFX & SWT 1
N Observer: update ruft nicht repaint auf AWT, Swing, JavaFX & SWT 0
C Repaint() funktioniert nicht in TabbedPanel AWT, Swing, JavaFX & SWT 5
S JList repaint AWT, Swing, JavaFX & SWT 1
L NullpointerException und Probleme mit repaint() AWT, Swing, JavaFX & SWT 11
M Repaint mittels Button richtig aufrufen klappt nicht AWT, Swing, JavaFX & SWT 1
B Repaint auf JFrame, JLabel und ImageIcon AWT, Swing, JavaFX & SWT 4
K 2D-Grafik Paint - Wie binde ich repaint ein? AWT, Swing, JavaFX & SWT 8
D repaint() klappt anders als vorgestellt AWT, Swing, JavaFX & SWT 15
R Repaint() in Schleifen, Threads AWT, Swing, JavaFX & SWT 13
B Swing Repaint Problem - mal wieder AWT, Swing, JavaFX & SWT 5
P 2D-Grafik Gezielter Repaint einzelner Frames in Java-Game AWT, Swing, JavaFX & SWT 6
javampir Bei repaint nix los AWT, Swing, JavaFX & SWT 2
B Swing repaint() AWT, Swing, JavaFX & SWT 3
Ernesto95 AnimationLoop - Problem bei Aufruf von repaint AWT, Swing, JavaFX & SWT 6
P 2D-Grafik repaint(); steigender RAM Verbauch AWT, Swing, JavaFX & SWT 6
Y KeyListener, GUI Thread, repaint AWT, Swing, JavaFX & SWT 7
S Applet Repaint AWT, Swing, JavaFX & SWT 3
M Programm hängt sich auf nachdem repaint() benutzt wurde AWT, Swing, JavaFX & SWT 2
R Swing Grafikfehler bei repaint AWT, Swing, JavaFX & SWT 2
N repaint() blockieren AWT, Swing, JavaFX & SWT 6
K canvas zeig nach repaint nichts an AWT, Swing, JavaFX & SWT 8
M Repaint() AWT, Swing, JavaFX & SWT 14
J Swing repaint, repaint, repaint AWT, Swing, JavaFX & SWT 8
M Applet repaint() verlangsamen AWT, Swing, JavaFX & SWT 7
R paintComponent malt bei repaint() Rahmen um Panel AWT, Swing, JavaFX & SWT 7
P EDT Problem? Kein Aufruf der repaint Methode AWT, Swing, JavaFX & SWT 6
V Applet JApplet Flackern durch Repaint AWT, Swing, JavaFX & SWT 11
kodela Problem mit repaint() AWT, Swing, JavaFX & SWT 3
N Swing Funktion repaint() updated nicht AWT, Swing, JavaFX & SWT 5
F repaint reagiert nicht AWT, Swing, JavaFX & SWT 8
S AWT Probleme mit repaint() AWT, Swing, JavaFX & SWT 2
D Repaint()? Oder was??? AWT, Swing, JavaFX & SWT 5
M Eine nicht korrekte Darstellung bei repaint() warum? AWT, Swing, JavaFX & SWT 4
T 2D-Grafik Kreis "von Hand" zeichnen -> jedesmal repaint()? AWT, Swing, JavaFX & SWT 6
R validate(), repaint funktionieren nicht! AWT, Swing, JavaFX & SWT 7
B AWT Canvas überdeckt nach repaint() JComboBox-Optionen AWT, Swing, JavaFX & SWT 2
B Swing verschachteltes GUI: repaint() ändert mehr als nur gewünschte Component AWT, Swing, JavaFX & SWT 4
S validate(), invalidate(), repaint(),... Was kommt wann? AWT, Swing, JavaFX & SWT 5
M 2D-Grafik repaint() löscht altes Bild nicht AWT, Swing, JavaFX & SWT 2
J repaint() nicht richtig? AWT, Swing, JavaFX & SWT 6
R repaint erzwingen AWT, Swing, JavaFX & SWT 3
Zettelkasten repaint() von anderen Klassen aufrufen AWT, Swing, JavaFX & SWT 4
H repaint()-Problem - 50% CPU-Auslastung AWT, Swing, JavaFX & SWT 4
P repaint während Thread läuft AWT, Swing, JavaFX & SWT 9
D Repaint Frage, Design Frage AWT, Swing, JavaFX & SWT 2
N Swing MainWindow(JFrame) aktualisieren(neuzeichnen) repaint AWT, Swing, JavaFX & SWT 4
T repaint() Problem AWT, Swing, JavaFX & SWT 2
A 2D-Grafik Repaint - Alternative? AWT, Swing, JavaFX & SWT 3
C JLabel, JTextArea, JScrollPane. repaint(); ? AWT, Swing, JavaFX & SWT 6
N Swing repaint() funktioniert nicht AWT, Swing, JavaFX & SWT 5
T Swing repaint funktioniert nur manchmal? AWT, Swing, JavaFX & SWT 6
K Jpanel repaint problem (Fullscreen) AWT, Swing, JavaFX & SWT 5
V Swing Bei repaint() tut sich nichts AWT, Swing, JavaFX & SWT 7
G ColorReader, bei Fadenkreuz zeichnen mit repaint() flackern AWT, Swing, JavaFX & SWT 19
I Canvas Repaint Probleme AWT, Swing, JavaFX & SWT 2
D Swing Actionlistener verhindert repaint?! AWT, Swing, JavaFX & SWT 2
S JLabel repaint AWT, Swing, JavaFX & SWT 8
C Swing Linux mag mein Swing-repaint() nicht... AWT, Swing, JavaFX & SWT 7
J Swing paintComponent() - repaint() - BufferedImage anzeigen AWT, Swing, JavaFX & SWT 5
Luk10 repaint() auch in anderen Klassen! AWT, Swing, JavaFX & SWT 6
A repaint() zu langsam, bitte um alternativen AWT, Swing, JavaFX & SWT 5
T Überlappende Transparenz und repaint() AWT, Swing, JavaFX & SWT 10
E EINFACHE Verständnisfrage zu repaint(), paintComponent(), usw. AWT, Swing, JavaFX & SWT 16
O Girdbag Formatierung nach repaint verloren AWT, Swing, JavaFX & SWT 2
E Swing - repaint() AWT, Swing, JavaFX & SWT 6
T Image wird nicht angezeigt?! - MediaTracker/repaint AWT, Swing, JavaFX & SWT 9
E AWT Problem mit Repaint (in Loop oder Timer) AWT, Swing, JavaFX & SWT 3
O Exception bei repaint AWT, Swing, JavaFX & SWT 3
D Fragen zu Swing, paintComponent() und repaint AWT, Swing, JavaFX & SWT 6
Dit_ Zeilenmarkierung verschwindet nach repaint() AWT, Swing, JavaFX & SWT 12
A Swing Infinite repaint loop unterbrechen AWT, Swing, JavaFX & SWT 7
hdi Swing EDT macht kein repaint() AWT, Swing, JavaFX & SWT 2
F "Verrutschen" von Komponenten bei repaint() AWT, Swing, JavaFX & SWT 9
Junker Fensterinhalt vor ausführen von repaint komplett löschen. AWT, Swing, JavaFX & SWT 2
T Fenster wird trotz repaint() und revalidate() nicht sofort neu gezeichnet AWT, Swing, JavaFX & SWT 6
E Graphics2D: altes Objekt löschen, wenn repaint aufgerufen wird AWT, Swing, JavaFX & SWT 7
J Swing Verständnis-Problem repaint(int x,int y,int width,int height) AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben