auf paintComponent() warten

syfds

Mitglied
Hallo an alle,

ich habe folgendes Problem: in einer Klasse A wird ein Grafik gezeichnet. In der Methode
Code:
paintComponent()
wird während der Zeichnung ein BufferedImage erstellt. Die Methode
Code:
 repaint();
wird von allen möglichen Stellen aufgerufen, d.h. dass
Code:
paintComponent()
Methode nicht gleich aufgerufen wird, sondern in RepaintManager durch
Code:
invokeLater()
.

Java:
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
Java:
A.repaint();
BuefferedImage img = A.getImage();

aufrufe, bekomme ich ab und zu ein nicht vollständig gezeichnetes Bild, da anscheinend noch die
Code:
paintComponent()
Methode ausgeführt wird, während ich das Bild abfrage.
Nun meine Frage, wie könnte ich auf das Ende der
Code:
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...

Top Contributor
In der Methode
Code:
paintComponent()
wird während der Zeichnung ein BufferedImage erstellt.
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

Top Contributor
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":
Java:
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

Mitglied
ich könnte das Bild aus Panel so erstellen:

Java:
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

Top Contributor
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:
Java:
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]
 
Zuletzt bearbeitet:

syfds

Mitglied
wäre es korrekt, wenn ich auf das Ende von
Code:
paintComponent()
Methode so warte:
Java:
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
Code:
paintComponent()
ausführt, d.h. wenn
Code:
repaintThread
fertig ist, sind somit auch alle dazugehörige Threads fertig? Verstehe ich es richtig?

mfg

Sergej
 

André Uhres

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

Marco13

Top Contributor
@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...
 

André Uhres

Top Contributor
@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

Top Contributor
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

Top Contributor
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

Mitglied
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...

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...

Code:
paintImmediately()
zeichnet ja sofort, ohne Verzögerung? Die Mehtode könnte ich anstatt
Code:
repaint()
benutzen?
 

syfds

Mitglied
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

Top Contributor
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

Top Contributor
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

Top Contributor
Code:
paintImmediately()
zeichnet ja sofort, ohne Verzögerung? Die Mehtode könnte ich anstatt
Code:
repaint()
benutzen?

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é
 
Zuletzt bearbeitet:

syfds

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

Java:
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
Code:
imagePanel
zeichne ich alle Element in ein Bild, das ich später mit
Code:
drawImage()
auf Panel zeichne.



Java:
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;
}

}


Java:
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
Code:
getImage()
zu liefern bekomme ich
Code:
NULL
.
Code:
invokeLater()
wird ja erst nach Abarbeitung von
Code:
paint()
Methode aufgerufen, und danach kann ja mein
Code:
getImage()
nicht null sein?
 
Zuletzt bearbeitet:

Michael...

Top Contributor
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?

Diese Methode funktioniert nicht vollständig. In meinem
Code:
imagePanel
zeichne ich alle Element in ein Bild, das ich später mit
Code:
drawImage()
auf Panel zeichne.
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

Mitglied
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?
Java:
BufferedImage image = new BufferedImage(width, height, type);
imagePanel.paint(image.getGraphics());

Du würdest sowas machen?
Java:
@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
Code:
paintComponent()
zu zeichnen?
 

Michael...

Top Contributor
Du würdest sowas machen?
Java:
@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());
}
Nein, ist ja das selbe wie vorhin nur in Grün -ausgelagert in eine Methode.

Was ich meinte war eher so etwas:
Java:
	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...)

Was ist denn so verkehrt, das Bild in
Code:
paintComponent()
zu zeichnen?
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

Mitglied
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
Code:
paint()
in EventQueue der Reihe nach ausgeführt werden. Du hast auf jeden Fall Recht!
 

bERt0r

Top Contributor
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());
 
Zuletzt bearbeitet:

André Uhres

Top Contributor
... 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

Top Contributor
Java:
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());
			}
		});

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

Top Contributor
@Andre, du hast natürlich recht, ich hab mich falsch ausgedrückt.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
imagePanel.repaint();
}
});

//An dieser Stelle liegt dein imagePanel.repaint() aufruf noch auf der "Todo-List" des EDT
//Jetzt ist es ein Rennen: kommt der EDT sofort dran und arbeitet deinen repaint() aufruf ab
//oder springt der Code hier in die nächste zeile und packt das paint hier drauf.
//Normalerweise dauert es länger, dass der EDT so ein Runnable abarbeitet und noch dazu dann der RepaintManager seine Arbeit macht
//als dass dein Code noch ein Runnable auf den EDT packt.
//Jetzt packt aber der RepaintManager wenn er fertig ist den paint() aufruf auch nochmal hinten auf die EDT Warteschlange
//Dann siehts normalerweise so aus: 1.<repaint()>2. <paint(image.getGraphics())> 3.<Runnable des RepaintManagers>

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

André Uhres

Top Contributor
//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.

//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

Top Contributor
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.

The runnable executes on the event dispatching thread and causes the component's RepaintManager to invoke paintImmediately() on the component, which does the following:

uses the clip rectangle and the opaque and optimizedDrawingEnabled properties to determine the 'root' component from which the paint operation must begin (to deal with transparency and potentially overlapping components).
if the root component's doubleBuffered property is true, and double-buffering is enabled on the root's RepaintManager, will convert the Graphics object to an appropriate offscreen graphics.
invokes paint() on the root component (which executes (A)'s JComponent.paint() steps #2-4 above), causing everything under the root which intersects with the clip rectangle to be painted.
if the root component's doubleBuffered property is true and double-buffering is enabled on the root's RepaintManager, copies the offscreen image to the component using the original on-screen Graphics object.
Schau ich hab dir ein Beispiel gemacht:
Java:
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

Top Contributor
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

Top Contributor
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

Top Contributor
Wenn ich eine Konstruktion habe wie
Java:
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.
Java:
component.repaint();
EventQueue.invokeLater(new Runnable()
{
  public void run()
  {
  boolean ergebnis=component.wasJustNowRepainted();
  }
}
 
Zuletzt bearbeitet:

André Uhres

Top Contributor
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

Mitglied
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:
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

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

Java:
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. :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
P paintComponent-Methode wird dauernd neu aufgerufen AWT, Swing, JavaFX & SWT 2
H new Operator in paintComponent - Speicherprobleme vorprogrammiert? AWT, Swing, JavaFX & SWT 2
frager2345 Warum paintComponent hier und nicht paint AWT, Swing, JavaFX & SWT 2
L paintComponent in Panel eines Borderlayouts hinzufügen AWT, Swing, JavaFX & SWT 3
G update, paintComponent AWT, Swing, JavaFX & SWT 1
H Transparent zeichnen mit drawImage in paintComponent Methode AWT, Swing, JavaFX & SWT 3
T Problem mit paintComponent() AWT, Swing, JavaFX & SWT 17
L Swing repaint() ruft paintComponent(g1d) nicht auf AWT, Swing, JavaFX & SWT 12
C Objekt an paintComponent weitergeben AWT, Swing, JavaFX & SWT 1
B 2D-Grafik paintcomponent Probleme beim zeichnen AWT, Swing, JavaFX & SWT 10
L 2D-Grafik Swing paint|paintComponent AWT, Swing, JavaFX & SWT 2
N JButton über benutzerdefinierte paintComponent setzen AWT, Swing, JavaFX & SWT 3
M Swing Swing-Widgets und paintComponent() AWT, Swing, JavaFX & SWT 2
K Probleme beim zeichnen mit paintComponent() AWT, Swing, JavaFX & SWT 1
D PaintComponent wird nicht aufgerufen AWT, Swing, JavaFX & SWT 3
S passende PaintComponent ? Zeichnen in TextArea mit Scrollpane ? AWT, Swing, JavaFX & SWT 2
I (JPanel) paintComponent mit Zeitverschiebung (Sleep/Wait) AWT, Swing, JavaFX & SWT 1
K Swing paintComponent, JPanel auslagern, ChangeEvents AWT, Swing, JavaFX & SWT 7
B Zeichnen mit paintComponent? Oder anders? AWT, Swing, JavaFX & SWT 15
B AWT paintComponent wird nur 2 mal ausgeführt?! AWT, Swing, JavaFX & SWT 5
P Paint und paintComponent AWT, Swing, JavaFX & SWT 12
D paintComponent() mit transparentem Hintergrund. AWT, Swing, JavaFX & SWT 0
G Swing Flackern nach Override von paintComponent() AWT, Swing, JavaFX & SWT 3
M Swing paintComponent in rekusivem JPanel funktioniert nicht AWT, Swing, JavaFX & SWT 2
M DefaultTableModel ruft paintComponent auf ! AWT, Swing, JavaFX & SWT 4
T Swing paintComponent(); AWT, Swing, JavaFX & SWT 24
K Swing JButton paintComponent überschreiben AWT, Swing, JavaFX & SWT 5
Kenan89 2D-Grafik paintComponent quetsch alles in Panel AWT, Swing, JavaFX & SWT 26
B 2D-Grafik paintComponent für rechteckigen Bereich? AWT, Swing, JavaFX & SWT 6
P Swing problem mit paintComponent AWT, Swing, JavaFX & SWT 2
R paintComponent malt bei repaint() Rahmen um Panel AWT, Swing, JavaFX & SWT 7
K paintComponent nicht aufgerufen AWT, Swing, JavaFX & SWT 2
J Mal wieder Probleme mit paintComponent AWT, Swing, JavaFX & SWT 3
L Swing 64bit Problem mit paint/paintComponent AWT, Swing, JavaFX & SWT 7
W JPanel Überschreiben // paintComponent? AWT, Swing, JavaFX & SWT 4
propra Wieso wird paintComponent() beim Start 2 malausgeführt? AWT, Swing, JavaFX & SWT 4
T BufferedImage bei paintComponent AWT, Swing, JavaFX & SWT 6
P JLabel paintComponent AWT, Swing, JavaFX & SWT 3
Z Swing paintcomponent und menbar Problem AWT, Swing, JavaFX & SWT 3
S Image wird nicht (immer) in paintComponent gezeichnet? AWT, Swing, JavaFX & SWT 6
R 2D-Grafik auf JPanel zeichen - ohne @Override paintComponent AWT, Swing, JavaFX & SWT 6
A Probleme mit paintComponent & BorderFactory AWT, Swing, JavaFX & SWT 2
A paintComponent AWT, Swing, JavaFX & SWT 4
T Rechtecke zeichnen mit paintComponent() AWT, Swing, JavaFX & SWT 3
R paintComponent direkt bei actionPerformed aufrufen AWT, Swing, JavaFX & SWT 2
P Swing Vom BufferedImage bei paintComponent nur soviel zeichnen, wie nötig AWT, Swing, JavaFX & SWT 3
P Swing Frage zu paintComponent/getGraphics AWT, Swing, JavaFX & SWT 4
A paintComponent() - Animation AWT, Swing, JavaFX & SWT 2
K JPanel und paintComponent AWT, Swing, JavaFX & SWT 8
E 2D-Grafik Zeichnen außerhalb der "paintComponent"-Methode? AWT, Swing, JavaFX & SWT 5
C Checkbox in Liste deaktivieren und paintComponent explizit aufrufen AWT, Swing, JavaFX & SWT 12
C Performance-Problem beim Überschreiben von paintComponent() AWT, Swing, JavaFX & SWT 2
P 2D-Grafik PaintComponent() übernimmt keine Werte aus update() AWT, Swing, JavaFX & SWT 8
F Swing Problem mit KeyListener||paintComponent() in JFrame AWT, Swing, JavaFX & SWT 12
P Game of Life - PaintComponent-Problem / Timer? AWT, Swing, JavaFX & SWT 8
B Anzeigefehler in GridBagLayout durch paintComponent(Graphics g) AWT, Swing, JavaFX & SWT 3
J Swing paintComponent() - repaint() - BufferedImage anzeigen AWT, Swing, JavaFX & SWT 5
J paintComponent() übergeben AWT, Swing, JavaFX & SWT 4
N paintComponent für Graphics ansprechen AWT, Swing, JavaFX & SWT 2
E EINFACHE Verständnisfrage zu repaint(), paintComponent(), usw. AWT, Swing, JavaFX & SWT 16
kodela Swing paintComponent() wird nicht aufgerufen AWT, Swing, JavaFX & SWT 19
E einfache Frage zu paintComponent und Graphics AWT, Swing, JavaFX & SWT 7
E WARUM wird paintComponent nicht aufgerufen? AWT, Swing, JavaFX & SWT 12
C paintComponent mit Maus verschieben - wie? AWT, Swing, JavaFX & SWT 2
G Swing paintComponent Effizienz? AWT, Swing, JavaFX & SWT 4
R paintComponent Kollision AWT, Swing, JavaFX & SWT 2
D Fragen zu Swing, paintComponent() und repaint AWT, Swing, JavaFX & SWT 6
A Probleme mit paintComponent() AWT, Swing, JavaFX & SWT 2
T Swing paintComponent problem AWT, Swing, JavaFX & SWT 3
MrGe getWidth(); getHeight(); außerhalb von paintComponent AWT, Swing, JavaFX & SWT 4
A paintComponent überdeckt ... AWT, Swing, JavaFX & SWT 13
JFeel-x repaint für Aufruf von paintComponent-Klasse ungeeignet? AWT, Swing, JavaFX & SWT 11
F Wer ruft paintComponent() Methode auf? AWT, Swing, JavaFX & SWT 9
@ JPanel: kein paintComponent() trotz repaint() AWT, Swing, JavaFX & SWT 4
G paintComponent Problem AWT, Swing, JavaFX & SWT 6
T paintComponent() überschreiben: Platz für Border freihalten? AWT, Swing, JavaFX & SWT 6
G paintComponent JPanel im JApplet AWT, Swing, JavaFX & SWT 2
X Speichern in der paintComponent() Methode AWT, Swing, JavaFX & SWT 15
W JLabel + paintComponent AWT, Swing, JavaFX & SWT 2
V Wieviel Logik in paintComponent? AWT, Swing, JavaFX & SWT 7
hdi super.paintComponent(g); soll nicht alles löschen AWT, Swing, JavaFX & SWT 2
G paintComponent() Methode für JPanel in NetBeans überschreibe AWT, Swing, JavaFX & SWT 2
L Problem mit paintComponent() under java < 1.6 under Windo AWT, Swing, JavaFX & SWT 3
H eigene paintComponent(Graphics) kommt mit rezise nicht klar AWT, Swing, JavaFX & SWT 6
N Probleme mit paintComponent und GradientPaint AWT, Swing, JavaFX & SWT 5
B JPanel#paintComponent(Graphics g) << flackert oO AWT, Swing, JavaFX & SWT 3
D performance problem: paintcomponent, alphacomp, bufferedImag AWT, Swing, JavaFX & SWT 10
A Probelme mit großen BufferedImage in paintComponent AWT, Swing, JavaFX & SWT 7
C Bei Skalierung wird paintComponent() nicht aufgerufen,warum? AWT, Swing, JavaFX & SWT 4
K Problem repaint()->paintComponent AWT, Swing, JavaFX & SWT 9
G paintComponent wird nicht dargestellt AWT, Swing, JavaFX & SWT 5
T Kuchendiagramm - mit paintComponent nach JButton druck zeich AWT, Swing, JavaFX & SWT 4
R paintComponent wird anscheinend nicht aufgerufen AWT, Swing, JavaFX & SWT 2
T JPanel mit paintComponent methode im JInternalFrame AWT, Swing, JavaFX & SWT 3
M super.paintComponent(g); aufrufen oder nicht? AWT, Swing, JavaFX & SWT 8
M Unterschied zwischen paintComponent() und paint()? AWT, Swing, JavaFX & SWT 4
D JTextArea in der paintComponent () hinzufügen? AWT, Swing, JavaFX & SWT 9
raptorrs J2D paintComponent: Nur ganzzahlige (-int) Werte möglich? AWT, Swing, JavaFX & SWT 3
B Schon wieder ein Problem mit paintComponent(). AWT, Swing, JavaFX & SWT 2
G Keine Anzeige von Grafik bei externem paintComponent-Aufruf AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben