# auf paintComponent() warten



## syfds (7. Dez 2011)

Hallo an alle,

ich habe folgendes Problem: in einer Klasse A wird ein Grafik gezeichnet. In der Methode 
	
	
	
	





```
paintComponent()
```
wird während der Zeichnung ein BufferedImage erstellt. Die Methode
	
	
	
	





```
repaint();
```
 wird von allen möglichen Stellen aufgerufen, d.h. dass 
	
	
	
	





```
paintComponent()
```
 Methode nicht gleich aufgerufen wird, sondern in RepaintManager durch 
	
	
	
	





```
invokeLater()
```
.  


```
class A extends JPanel{
 private BufferedImage img;

@Override
public void paintComponent(Graphics g){
...//Logik, img wird initialisiert

 }
 public BufferedImage getImage(){ return this.img}	
}
```

Also wenn ich 

```
A.repaint();
BuefferedImage img = A.getImage();
```

aufrufe, bekomme ich ab und zu ein nicht vollständig gezeichnetes Bild, da anscheinend noch die 
	
	
	
	





```
paintComponent()
```
 Methode ausgeführt wird, während ich das Bild abfrage.
Nun meine Frage, wie könnte ich auf das Ende der 
	
	
	
	





```
paintComponent()
```
Methode warten, bzw. welchen Thread muss ich abwarten?

Ich habe schon alles mögliche ausprobiert, aber mir hat leider nichts geholfen. Für mich wäre jeder Hinweis sehr hilfreich! Danke im voraus!

Sergej


----------



## Michael... (7. Dez 2011)

syfds hat gesagt.:


> In der Methode
> 
> 
> 
> ...


Gibt es da keine andere Möglichkeit? Was wird denn auf das Image gezeichnet? Die paintComponent ist nicht gerade ein günstiger Ort dafür, vor allem wenn man das Bild an anderer Stelle benötigt. Aber das hast Du ja bereits selbst festgestellt ;-)


----------



## Marco13 (7. Dez 2011)

Ja, Michael... hat recht, das klingt nach einem Fehler im Konzept. Man könnte jetzt zwar über mögliche Workarounds spekulieren (z.B. ein "Double Buffering":

```
private BufferedImage frontBuffer...
private BufferedImage backBuffer...

void paintComponent(...)
    paintInto(backBuffer);

    // Ganz am Ende:
    BufferedImage temp = frontBuffer;
    frontBuffer = backBuffer;
    backBuffer = temp;
}

BufferedImage getImage() { return frontBuffer; }
```
) aber das sieht insgesamt ziemlich krampfig aus, und könnte andere Nachteile und Glitches haben...


----------



## syfds (7. Dez 2011)

ich könnte das Bild aus Panel so erstellen:


```
BufferedImage img = new BufferedImage(A.getWidth(), A.getHeight(), BufferedImage.TYPE_INT_RGB);
A.paint(img.getGraphics());
```

Hier hab ich das Problem, dass ich nich weiß wann mein Panel mit Zeichnen fertig ist. Und so kann ich noch nicht fertiges Panel ins Bild zeichnen, was wiederum ein nich vollständiges Bild liefert.


----------



## bERt0r (7. Dez 2011)

Die sache mit Containern und ihrer tatsächlichen Größe sind immer so eine Sache... Hab grad versucht auf die schnelle ein Beispiel zu schreiben und gehakt hats, Size=0. Doch plötzlich gehts, obwohl ich nix geändert hab. Manchmal glaub ich Eclipse spielt Streiche mit mir:

```
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class GraphPanel extends JPanel{
	BufferedImage img;
	public GraphPanel() 
	{
		super();
	}
	
	public void paintCompoennt(Graphics g)
	{
		super.paint(g);
	}
	
	public BufferedImage getImage()
	{
		this.revalidate();
		Dimension r=this.getSize();
		BufferedImage i=new BufferedImage(r.width,r.height,BufferedImage.TYPE_3BYTE_BGR);
		this.paint(i.getGraphics());
		return i;
	}
	
	
	public static void main(String args[])
	{
		class MyActionListener implements ActionListener
		{
			JLabel lbl;
			GraphPanel panel;
			MyActionListener(JLabel l,GraphPanel p)
			{
				lbl=l;
				panel=p;
			}
			
			public void actionPerformed(ActionEvent e)
			{
				lbl.setIcon(new ImageIcon(panel.getImage()));
				((JFrame)panel.getTopLevelAncestor()).pack();
			}
		}

		EventQueue.invokeLater(new Runnable()
		{
			public void run()
			{
				JFrame frame=new JFrame("Blah");
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				GraphPanel gp=new GraphPanel();
				JLabel lbl=new JLabel("Hallo Welt");
				JLabel imgLabel=new JLabel();
				JButton showImage=new JButton("Show Image");
				showImage.addActionListener(new MyActionListener(imgLabel,gp));
				
				gp.add(lbl);
				gp.add(showImage);
				
				frame.add(gp,BorderLayout.NORTH);
				frame.add(imgLabel,BorderLayout.CENTER);
			
				frame.setVisible(true);
				frame.pack();
			}
		});	
	}
}
```
[EDIT]Ich hatte das panel nicht geaddet omg.[/EDIT]


----------



## syfds (8. Dez 2011)

wäre es korrekt, wenn ich auf das Ende von 
	
	
	
	





```
paintComponent()
```
 Methode so warte:

```
Thread repaintThread = new Thread(new Runnble(){

@Override
public void run(){

A.repaint();
}

});
repaintThread.start();

while(repaintThread.isAlive()){
Thread.sleep(500);
}

//hier ist repaint fertig
```

im Thread repaintThread läuft ja noch ein Thread, der die Methode 
	
	
	
	





```
paintComponent()
```
 ausführt, d.h. wenn 
	
	
	
	





```
repaintThread
```
fertig ist, sind somit auch alle dazugehörige Threads fertig? Verstehe ich es richtig?

mfg

Sergej


----------



## André Uhres (8. Dez 2011)

```
panel.repaint();
SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        //hier ist repaint fertig
    }
});
```
Gruß,
André


----------



## Marco13 (8. Dez 2011)

@André: Sicher? Intuitiv würde man sagen: "Ja, es muss fertig sein, weil's vom EDT abgearbeitet wird" und so. Aber Events haben unterschiedliche Prioritäten, und gerade PaintEvents werden ja "coalesced", d.h. bei 1000 repaints wird u.U. nur EINmal paintComponent aufgerufen - und es ist wohl schwer, zu sagen, wann... Also, es könnte sein, dass das so funktioniert, aber 100% sicher wäre ich mir nicht...


----------



## syfds (8. Dez 2011)

André Uhres hat gesagt.:


> ```
> panel.repaint();
> SwingUtilities.invokeLater(new Runnable() {
> @Override
> ...



Hi Andre,

ich hab grad ausprobiert, es hilft nicht, ab und zu werden Bilder nicht gezeichnet. Weißt du woran es ungefähr liegen könnte?


----------



## Marco13 (8. Dez 2011)

Beschreib' nochmal genauer, was du eigentlich erreichen willst....


----------



## André Uhres (8. Dez 2011)

Marco13 hat gesagt.:


> @André: Sicher? Intuitiv würde man sagen: "Ja, es muss fertig sein, weil's vom EDT abgearbeitet wird"



Ja, Du liegst schon richtig mit Deiner Intuition . Der RepaintManager kann nämlich nur dann eine Serie von Malanträgen zusammenfassen, wenn der "Anführer" der Serie schon mit invokeLater verschickt wurde, aber noch nicht auf dem EDT verarbeitet wurde.

Gruß,
André


----------



## Marco13 (8. Dez 2011)

OK, das sind dann Details die ich auch erst nochmal im Code hätte nachvollziehen müssen... aber anscheinend hat's ja nicht geholfen. Ich dachte einen Moment, ob vielleicht paintImmediately helfen könnte, aber habe es selbst noch nicht benutzt - und gehe nach wie vor davon aus, dass ein Designfehler der ursächliche Grund für die Frage ist...


----------



## bERt0r (8. Dez 2011)

Ich versteh auch nicht ganz wozu du auf die paintComponent Methode warten willst. Schau dir mein Beispiel an, das funktioniert einwandfrei so wie du (denke ich jedenfalls) es haben willst.


----------



## syfds (8. Dez 2011)

Marco13 hat gesagt.:


> OK, das sind dann Details die ich auch erst nochmal im Code hätte nachvollziehen müssen... aber anscheinend hat's ja nicht geholfen. Ich dachte einen Moment, ob vielleicht paintImmediately helfen könnte, aber habe es selbst noch nicht benutzt - und gehe nach wie vor davon aus, dass ein Designfehler der ursächliche Grund für die Frage ist...





Marco13 hat gesagt.:


> OK, das sind dann Details die ich auch erst nochmal im Code hätte nachvollziehen müssen... aber anscheinend hat's ja nicht geholfen. Ich dachte einen Moment, ob vielleicht paintImmediately helfen könnte, aber habe es selbst noch nicht benutzt - und gehe nach wie vor davon aus, dass ein Designfehler der ursächliche Grund für die Frage ist...




```
paintImmediately()
```
 zeichnet ja sofort, ohne Verzögerung? Die Mehtode könnte ich anstatt 
	
	
	
	





```
repaint()
```
benutzen?


----------



## syfds (8. Dez 2011)

bERt0r hat gesagt.:


> Ich versteh auch nicht ganz wozu du auf die paintComponent Methode warten willst. Schau dir mein Beispiel an, das funktioniert einwandfrei so wie du (denke ich jedenfalls) es haben willst.



ich muss paintComponent() abwarten, um ein Bild vom Panel erstellen zu können, und ich kann es erst dann tun, wenn die Zeichnung fertig gemalt ist, um ein vollständiges Bild zu exportieren.


----------



## Marco13 (8. Dez 2011)

Dafür gibt es auch andere Möglichkeiten. Das oeben angedeutete Double-Buffering, oder direkt 
component.paint(graphicsFromBufferedImage);
aufrufen, oder ähnliches. Natürlich könnte man auch in paintComponent irgendwelche Semaphoren setzen oder so, aber das klingt hakelig...


----------



## bERt0r (8. Dez 2011)

Nein musst du nicht, weil dein Ansatz komplett falsch ist. In der paintComponent Methode hast du nichts anderes zu tun als zu zeichnen. Wenn du mit component.paint(image.getGraphics()) dein Image erstellst, läuft das ganze meines Wissens nicht mal auf dem EDT und die Methode springt erst dann zurück, wenn das Bild fertig ist.


----------



## André Uhres (9. Dez 2011)

syfds hat gesagt.:


> ```
> paintImmediately()
> ```
> zeichnet ja sofort, ohne Verzögerung? Die Mehtode könnte ich anstatt
> ...



Programme sollten diese Methode nicht direkt aufrufen, es sei denn, es gibt eine tatsächliche Notwendigkeit zum Zeichnen in Echtzeit. Das ist so, weil durch das asynchrone repaint() mehrfache überlappende Anträge leistungssteigernd zusammengefasst werden, während das bei Direktaufrufen von paintImmediately() nicht geschieht. Zusätzlich ist die Richtlinie für das Aufrufen dieser Methode, daß sie auf dem "event dispatching thread" aufgerufen werden muß; es ist keine API, die für den "multi-threading" Deines Malcodes bestimmt ist. 

Gruß,
André


----------



## syfds (12. Dez 2011)

das einzige, was mir fehlt, ist einfach abzuwarten, bis mein Panel vollständig gezeichnet wurde:


```
SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				
				imagePanel.repaint();
				
				
			}
		});


//an dieser Stelle ist mein Panel vollständig gezeichnet?

SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				//hier mache ich ein Image von meinem Panel
				final BufferedImage image= new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
imagePanel.paint(image.getGraphics());
			}
		});
```


Diese Methode funktioniert nicht vollständig. In meinem 
	
	
	
	





```
imagePanel
```
 zeichne ich alle Element in ein Bild, das ich später mit 
	
	
	
	





```
drawImage()
```
 auf Panel zeichne. 




```
public class ImagePanel extends JPanel{...
BufferedImage image;

public void paintComponent(Graphics g){
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics imageGraphics = image.getGraphics();

...
//hier werden alle Elemente gezeichnet
shapes.draw(imageGraphics);

...
//danach wird das Bild gezeichnet
g.drawImage(image, 0,0, this);

}

public BufferedImage getImage(){

return image;
}

}
```



```
SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				
				imagePanel.repaint();
				
			}
		});


//an dieser Stelle ist mein Panel vollständig gezeichnet?

SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {

			
//im == null, obwohl ich davor repaint() aufrufe?  	
BufferedImage im = imagePanel.getImage();
			}
		});
```

Wenn ich hier versuche, mir das Bild mittels 
	
	
	
	





```
getImage()
```
 zu liefern bekomme ich 
	
	
	
	





```
NULL
```
. 
	
	
	
	





```
invokeLater()
```
 wird ja erst nach Abarbeitung von 
	
	
	
	





```
paint()
```
 Methode aufgerufen, und danach kann ja mein 
	
	
	
	





```
getImage()
```
 nicht null sein?


----------



## Michael... (12. Dez 2011)

Mir sind die Anforderungen bzw. das Vorhaben immer noch nicht klar. Was heißt "auf die paintComponent(...) warten"? Auf den ersten Aufruf, den zweiten... Man gekommt doch garnicht mit wie oft und wann paintComponent aufgerufen wird- auf den wievielten Aufruf will man dann warten? Und wieso sollte man überhaupt warten?



syfds hat gesagt.:


> Diese Methode funktioniert nicht vollständig. In meinem
> 
> 
> 
> ...


Ich würde das Image nicht in der paintComponent malen (bzw. kannst Du vernünftige Gründe nennen, warum das Bild in der paintComponent erstellt und gemalt werden soll?) Könnte man das Bild nicht "ausserhalb" erstellen und bemalen und dann anschließend einfach nur repaint() aufrufen, damit in der paintComponent nur das Bild per drawImage gezeichnet wird?


----------



## syfds (12. Dez 2011)

Michael... hat gesagt.:


> Mir sind die Anforderungen bzw. das Vorhaben immer noch nicht klar. Was heißt "auf die paintComponent(...) warten"? Auf den ersten Aufruf, den zweiten... Man gekommt doch garnicht mit wie oft und wann paintComponent aufgerufen wird- auf den wievielten Aufruf will man dann warten? Und wieso sollte man überhaupt warten?
> 
> 
> Ich würde das Image nicht in der paintComponent malen (bzw. kannst Du vernünftige Gründe nennen, warum das Bild in der paintComponent erstellt und gemalt werden soll?) Könnte man das Bild nicht "ausserhalb" erstellen und bemalen und dann anschließend einfach nur repaint() aufrufen, damit in der paintComponent nur das Bild per drawImage gezeichnet wird?



Ja das könnte man machen, es geht mir jetzt ehrlich gesagt um keine konkrete Lösung. Ich will nur verstehen, warum mein Ansatz nicht funktioniert. Wenn ich versuche mein JPanel in ein Bild zu zeichnen, egal zu welchem Zeitpunkt, muss es doch gehen? 

```
BufferedImage image = new BufferedImage(width, height, type);
imagePanel.paint(image.getGraphics());
```

Du würdest sowas machen? 

```
@Override
public void paintComponent(Graphics g){

BufferedImage image = new BufferedImage(width, height, type);
initImage(image);
g.drawImage(image, 0,0, this);

}

private void initImage(BufferedImage image){
shapes.paint(image.getGraphics());
}
```

Was ist denn so verkehrt, das Bild in 
	
	
	
	





```
paintComponent()
```
 zu zeichnen?


----------



## Michael... (12. Dez 2011)

syfds hat gesagt.:


> Du würdest sowas machen?
> 
> ```
> @Override
> ...


Nein, ist ja das selbe wie vorhin nur in Grün -ausgelagert in eine Methode.

Was ich meinte war eher so etwas:

```
public void updateImage() {
		image = new BufferedImage(width, height, type);
		...
		repaint();
	}
	
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (img != null)
			g.drawImage(img, 0, 0, null);
	}
```
Wann und wie updateImage() aufgerufen wird, müsste noch definiert werden (z.B. beim Vergrößern oder Verkleinern der Komponente...)



syfds hat gesagt.:


> Was ist denn so verkehrt, das Bild in
> 
> 
> 
> ...


Ein Bild zu zeichnen kann u.U. etwas dauern. Aktionen innerhalb der paintComponent sollten möglichst wenig zeitaufwendig sein, um nicht unnötig zu blockieren. In dem Bsp. Code ist es sogar so, dass bei jedem Neuzeichnen ein neues Bild erstellt wird.


----------



## syfds (12. Dez 2011)

> Ein Bild zu zeichnen kann u.U. etwas dauern. Aktionen innerhalb der paintComponent sollten möglichst wenig zeitaufwendig sein, um nicht unnötig zu blockieren. In dem Bsp. Code ist es sogar so, dass bei jedem Neuzeichnen ein neues Bild erstellt wird.


Weil ja alle Aufrufe von
	
	
	
	





```
paint()
```
 in EventQueue der Reihe nach ausgeführt werden. Du hast auf jeden Fall Recht!


----------



## bERt0r (12. Dez 2011)

Nicht nur das, wenn du repaint machst, sammelt sich der RepaintManager die Anfragen ja zusammen. Du kannst dir nie wirklich sicher sein ob paintComponent tatsächlich ausgeführt wurde, auch wenn du ein invokeLater machst.
Und ja, ein Image in der paintComponent zu erzeugen ist normalerweise ganz übel, auch performancemäßig.


> The RepaintManager
> 
> The purpose of Swing's RepaintManager class is to maximize the efficiency of repaint processing on a Swing containment hierarchy, and also to implement Swing's 'revalidation' mechanism (the latter will be a subject for a separate article). It implements the repaint mechanism by intercepting all repaint requests on Swing components (so they are no longer processed by the AWT) and maintaining its own state on what needs to be updated (known as "dirty regions"). Finally, it uses invokeLater() to process the pending requests on the event dispatching thread, as described in the section on "Repaint Processing" (option B).


Das heißt, wenn du Pech hast wird dein Code so verarbeitet: repaint(); -> RepaintManager-> ich wart mal kurz; ->invokeLater(getImage); -> RepaintManager.invokeLater(paint());


----------



## André Uhres (13. Dez 2011)

bERt0r hat gesagt.:


> ... wenn du Pech hast wird dein Code so verarbeitet: repaint(); -> RepaintManager-> ich wart mal kurz; ->invokeLater(getImage); -> RepaintManager.invokeLater(paint());



Nein, der RepaintManager macht den invokeLater sofort (*)! Er wird eine Serie von Malanträgen dann zusammenfassen, wenn der "Anführer" der Serie mit invokeLater verschickt wurde, aber noch nicht auf dem EDT verarbeitet wurde. Der Vorgang bleibt immer "threadsafe"!

Gruß,
André

(*) sonst könnte der Mechanismus übrigens gar nicht funktionieren!


----------



## André Uhres (13. Dez 2011)

syfds hat gesagt.:


> ```
> SwingUtilities.invokeLater(new Runnable() {
> 
> @Override
> ...



Das erste "invokeLater" ist hier überflüssig, da "repaint" eh auf den EDT landet. Bei [c]imagePanel.paint(image.getGraphics());[/c] wäre "print" statt "paint" angebracht, weil "print" den Status der Komponente so setzt, dass der Doppelpuffer nicht benutzt wird: das Malen geschieht direkt auf den "Graphics", die übergeben werden. 

Gruß,
André


----------



## bERt0r (14. Dez 2011)

@Andre, du hast natürlich recht, ich hab mich falsch ausgedrückt.


> SwingUtilities.invokeLater(new Runnable() {
> @Override
> public void run() {
> imagePanel.repaint();
> ...


----------



## André Uhres (14. Dez 2011)

bERt0r hat gesagt.:


> //Jetzt packt aber der RepaintManager wenn er fertig ist den paint() aufruf auch nochmal hinten auf die EDT Warteschlange


Das wird er sicher nicht tun, denn dieser "paint" umgeht den "repaint"-Mechanismus! Aus diesem Grund sollte "paint" auch nie direkt aufgerufen werden. Hier sollten wir "print" statt "paint" verwenden.



bERt0r hat gesagt.:


> //Dann siehts normalerweise so aus: 1.<repaint()>2. <paint(image.getGraphics())> 3.<Runnable des RepaintManagers>


Nein, der Ablauf ist so:
1.<repaint()> 2.<Runnable des RepaintManagers> 3.<paint(image.getGraphics())>
Aber, wie gesagt, hier sollten wir auf jeden Fall "print" statt "paint" benutzen (die Tatsache, dass "paint" den Doppelpuffer benutzt, könnte uns einen Streich spielen)!!

Gruß,
André


----------



## bERt0r (14. Dez 2011)

Tut mir leid aber das stimmt einfach nicht.


> (B) The paint request originates from a call to repaint() on an extension of javax.swing.JComponent:
> 
> JComponent.repaint() registers an asynchronous repaint request to the component's RepaintManager, which *uses invokeLater() to queue a Runnable to later process the request* on the event dispatching thread.
> 
> ...


Schau ich hab dir ein Beispiel gemacht:

```
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class RepaintTest extends JPanel {

	private JLabel text;
	@Override
	public void paintComponent(Graphics g)
	{
		//Simuliere langes Paint
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Paint Component");
		super.paintComponent(g);
		
		
	}
	public static void main(String[] args) 
	{
		JFrame frame=new JFrame();
		final RepaintTest panel=new RepaintTest();
		final JLabel imgLabel=new JLabel();
		final JLabel imgLabel2=new JLabel();
		final JLabel imgLabel3=new JLabel();
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					JFrame frame = new JFrame();
					frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
					frame.setBounds(100, 100, 450, 300);
					frame.add(panel,BorderLayout.NORTH);
					frame.add(imgLabel,BorderLayout.CENTER);
					frame.add(imgLabel2,BorderLayout.SOUTH);
					frame.setVisible(true);					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});	

		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				System.out.println("Repaint");
				panel.setText("Repaint");
				panel.repaint();
			}
		});

		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				System.out.println("Paint on Image 1");
				BufferedImage image= new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
				Graphics g=image.createGraphics();
				panel.print(g);
				g.dispose();
				imgLabel.setIcon(new ImageIcon(image));
			}
		});	

		SwingUtilities.invokeLater(new Runnable()
		{
			@Override
			public void run()
			{
				System.out.println("So funktionierts");
				panel.setText("So funktionierts");
				panel.repaint();
				EventQueue.invokeLater(new Runnable()
				{
					@Override
					public void run()
					{
						System.out.println("Paint on Image 2");
						BufferedImage image= new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
						Graphics g=image.createGraphics();
						panel.paint(g);
						g.dispose();
						imgLabel2.setIcon(new ImageIcon(image));
					}
				}
						);
			}
		});
	}
	public RepaintTest() {	
		text=new JLabel("Init");
		this.add(text);
	}
	public void setText(String t)
	{
		text.setText(t);
	}
}
```
Ob du jetzt paint oder print macht nicht wirklich den Unterschied, wenn das mit dem Doublebuffern stimmt ist es wohl die korrektere Methode. Ausserdem hab ich grad die Methode isPaintingForPrint gefunden mit der man die Sache vielleicht sogar besser lösen kann.


----------



## Marco13 (14. Dez 2011)

Ohne alles aus den letzten beiträgen nachvollzogen zu haben (ich gehe immernoch davon aus, dass da was am Konzept nicht stimmt) : Eigentlich sollte man Components (so, wie es hier im Thread AFAIK gewünscht war) mit SwingUtilities (Java Platform SE 6) zeichnen können. Die Methode hat ihre Tücken, deswegen muss man da aufpassen. Auf jeden Fall verwendet sie intern eine CellRendererPane, und DIE wiederum verwendet 'paint', aber setzt für das Zeichnen die Component vorher explizit auf setDoubleBuffered(false) (kann man sich im Code ansehen)


----------



## André Uhres (14. Dez 2011)

bERt0r hat gesagt.:


> Tut mir Leid aber das stimmt einfach nicht.



Ich ging einfach nur davon aus, dass alles auf dem EDT gestartet wird. Das Problem bei deinem Beispiel besteht darin, dass die "invokeLater" Konstrukte alle auf dem "initial thread" gestartet werden, bis auf den letzten, bei dem es ja dann auch funktioniert. (Eine andere Möglichkeit wäre, den "repaint"-Antrag in ein "invokeAndWait" Konstrukt zu packen.)

Gruß,
André


----------



## bERt0r (15. Dez 2011)

Wenn ich eine Konstruktion habe wie

```
EventQueue.invokeAndWait(new Runnable
{
  public void run()
  {
  component.repaint();
  boolean ergebnis=component.wasJustNowRepainted();
  }
}
```
Angenommen die wasJustNowRepainted Funktion liefert das was sie soll, kommt dabei immer false raus. Der Repaint manager packt seine ganze Arbeit genau wie wir in ein Runnable und hängts mit invokeLater an den EDT ran.

Das heisst wir müssen erstmal warten, bis der repaint Aufruf durch ist, und danach hinten an den EDT unsere Funktion anhängen. Dazu könnten wir den repaint Aufruf jetzt mit invokeAndWait auf den EDT schicken, das ist aber gar nicht nötig. Repaint wurde gerade so konzipiert, dass es nicht auf dem EDT laufen muss, weil die Funktion ja selber einen Aufruf auf dem EDT erzeugt.

```
component.repaint();
EventQueue.invokeLater(new Runnable()
{
  public void run()
  {
  boolean ergebnis=component.wasJustNowRepainted();
  }
}
```


----------



## André Uhres (15. Dez 2011)

Ein Thread, der den Zugriff auf den GUI Status braucht, kann dazu "invokeAndWait" benutzen, weil diese Methode für solche Fälle konzipiert wurde.

Gruß,
André


----------



## bossa (1. Feb 2013)

Ich habe exakt das selbe Problem und bin schon mal froh, diesen Thread hier gefunden zu haben. Folgendes fand ich eigentlich sehr schön vom konzeptionellen Ansatz:


Michael... hat gesagt.:


> Ich würde das Image nicht in der paintComponent malen (bzw. kannst Du vernünftige Gründe nennen, warum das Bild in der paintComponent erstellt und gemalt werden soll?) Könnte man das Bild nicht "ausserhalb" erstellen und bemalen und dann anschließend einfach nur repaint() aufrufen, damit in der paintComponent nur das Bild per drawImage gezeichnet wird?



Damit braucht man sich um nichts mehr in der Hinsicht kümmern. paintComponent malt nur das Bild und es orgenisiert sich von ganz allein.



Aber jetzt meine Frage:
Wie erstelle und male ich "außerhalb" ein Bild? Konkret geht es bei mir darum auf einem eingeladenen Bild flächend halbtransparent einzufärben. Also brauch ich auch Graphics2D. Wie kann ich denn mein Bild woanders zusammensetzen, wenn nicht in einer überschriebenen Paint-Methode?


----------



## bossa (1. Feb 2013)

OK, alles klar, hab's kapiert. Ich male einfach auf das Graphics-Objekt


```
BufferedImage bi = new BufferedImage(laenge, breite, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();    

g2d.drawLine(xPos, yPos, laenge, breite);
```

das Bild bi kann ich dann einfach später in paintComponent() malen.

Wunderbar.


----------

