# Gradient Hintergrund malen und durchscheinen lassen



## Lequ (25. Apr 2012)

Hallo Zusammen,

ich baue gerade eine Oberfläche für eine Gui Anwendung. Dabei dachte ich mir, der schnöde, graue Hintergrund ist mir auf Dauer zu langweilig. Da wollte ich einen Kreis-Farbübergang (RadialGradientPaint) über den ganzen Hintergrund malen. Soweit die Theorie.

Problem dabei ist, der Hintergrund wird von irgend etwas überlagert. Der Panel der dem Frame hinzugefügt wurde ist schon auf setOpaque(false), ist jedoch komplett ohne Effekt diese Zeile.

Wenn die Zeile super.paint(g) auskommentiert wird, kann man sehen, wie es aussehen soll. Nur darüber sollen die restlichen Komponenten eben auch gezeigt werden.

Das witzige ist folgendes: während dem Resizing vom Fenster wird der Hintergrund gezeichnet, sobald das resizing fertig ist, kommt wieder der Vordergrund, flackert also ganz hübsch...

Weiß jemand woran das liegt?


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;

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

@SuppressWarnings("serial")
public class Test extends JFrame{

	public Test(){
		setSize(400,300);
		setVisible(true);
		JPanel middlePanel = new JPanel();
		middlePanel.setOpaque(false);
		middlePanel.add(new JButton("I am legend"));
		add(middlePanel);
	}
	
	public void paint(Graphics g) {
		Point2D center = new Point2D.Float(getWidth() / 2, getHeight() / 3);
		float radius = Math.max(getWidth(), getHeight()) / 2;
		float[] dist = { 0.0f, 1.0f };
		Color[] colors = { Color.white, Color.blue };
		RadialGradientPaint gradientPaint = new RadialGradientPaint(center, radius, dist, colors);
		
		Graphics2D g2d = (Graphics2D) g;
		g2d.setPaint(gradientPaint);
		g2d.fillRect(0, 0, getWidth(), getHeight());

		super.paint(g); // diese Zeile zum Test auskommentieren
        }
	
	public static void main(String[] args) {
		new Test();
	}

}
```

Viele Grüße


----------



## vanny (25. Apr 2012)

Überschreib die paintComponent(); von einem JPanel und adde das auf den JFrame.

Gruß Vanny


----------



## JavaProfi (25. Apr 2012)

How to do it wrong!

Schaue mal hier-->
http://www.java-forum.org/awt-swing-swt/43939-zeichnen-swing-tutorial.html#post272862

Gruß
JP


----------



## Lequ (25. Apr 2012)

@vanny: gibt es einen Unterschied ob ich paint überschreibe, was eignes zeichne und dann super.paint aufrufe oder ich das Ganze mit paintComponent mache? Meines Wissens ruft paint ja nur paintcomponents, paintchildren und paintborder auf (keine Gewähr bei der Reihenfolge  )

Mit dem neuen BackgroundPanel der das Zeichnen übernimmt funktionierts dann auch.

@JavaProfi: ich dachte wohl, wenn ich das obere Panel durchsichtig mache kommt der Hintergrund durch. Meiner jetzigen Vermutung nach ist das Problem, das der paint-Aufruf danach ein clearRect drinne hat und somit mein Hintergrund ziemlich unnötig ist. Der zusätzliche Panel übermalt den Hintergrund innerhalb seiner paint bzw paintcomponent wohl nicht. Hab ich das soweit richtig aufgefasst? 

Grüße


----------



## GUI-Programmer (25. Apr 2012)

Lequ hat gesagt.:
			
		

> gibt es einen Unterschied ob ich paint überschreibe, was eignes zeichne und dann super.paint aufrufe oder ich das Ganze mit paintComponent mache? Meines Wissens ruft paint ja nur paintcomponents, paintchildren und paintborder auf (keine Gewähr bei der Reihenfolge )



Bis aufs nur, ja, stimmt. Wenn du es genau wissen willst, dann schau dir einfach mal den Code an im src.zip deines jdks

Außerdem weisst du ja sicherlich, dass zuerst das gezeichnet wird, was auch zuerst im Code steht, wäre ja auch blöd, wenn nicht. Wenn du somit paintComponent überschreibst solltest du auch erst die super Methode aufrufen. Danach kannst du auf deiner Komponente sonst noch was weiterzeichnen. Würdest du das in der paint-Methoden machen, dann würde dies imo auch gezeichnet selbst wenn sich weitere Kindskomponenten in deiner Zeichenkomponente befänden.


----------



## Lequ (25. Apr 2012)

GUI-Programmer hat gesagt.:


> Wenn du somit paintComponent überschreibst solltest du auch erst die super Methode aufrufen.




Das war genau der Gedanke, der für mich Falsch war. Denn ich will ja den Hintergrund zeichnen und danach alles andere darüber. Wenn ich erst alles zeichnen lasse und dann den Hintergrund male, gibt es ja keinen Vordergrund mehr.

Was meiner Ansicht nach nun mein Problem gelöst hat ist die Tatsache, dass im paint von einem JPanel, im Gegensatz zum JFrame, kein eingener Hintergrund gemalt wird, der meinen zuvor gezeichneten Hintergrund übermalt. Stimmt diese Annahme?


----------



## GUI-Programmer (25. Apr 2012)

Versteh ich jetzt nicht genau (aber vielleicht andere!). Aber noch mal:
Wie bereits erwähnt rut paint() nur all die anderen Zeichenmethoden auf, zuerst paintComponent, dann paintBorder (klar, zeichnet den Rand) und danach paintChildren, was alle """geaddeten""" Komponenten zeichnen lässt.

Im Falle eines deckhaften JPanel wird in paintComponent nicht viel mehr gemacht als den Hintergrund mit der Hintergrundfarbe zu füllen, wenn ich mich nicht täusche. Folglich eignet sich sich das überschreiben der paintComponet sehr wohl für deinen Fall. Denn wenn du die Kompente nicht deckhaft machst, mit setOpaque(false), wird im Falle des JPanels eh {[(evtl. so gut wie)]} gar nichts in der super.paintComponent gezeichnet.

*EDIT:*


> Das war genau der Gedanke, der für mich Falsch war. Denn ich will ja den Hintergrund zeichnen und danach alles andere darüber. Wenn ich erst alles zeichnen lasse und dann den Hintergrund male, gibt es ja keinen Vordergrund mehr.



Um noch mal speziell darauf einzugehen: alles andere darüber bedeutet in etwa bei einem deckhaften JPanel 
	
	
	
	





```
g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight());
```
. Somit würdest du nichts vom einem selbst - vorher - gezeichneten Bild sehen. Und Foreground hat bei einem JPanel nun mal nichts.


----------



## vanny (25. Apr 2012)

Lequ hat gesagt.:


> @vanny: gibt es einen Unterschied ob ich paint überschreibe,...



Ja den gibt es. So wie ich es dir vorgeschlagen habe funktioniert es ^^.

Gruß Vanny


----------



## Lequ (26. Apr 2012)

Was ich nun gelernt habe: 
- ein JFrame hat kein paintComponent, deshalb benötigt man ein weiteren JPanel im Hintergrund dessen paintComponent man überschreiben kann
- wenn man man paint oder ähnliches überschreibt, sollte der entsprechende super aufruf am Anfang stehen und danach die Eigenzeichnung angefügt werden. Selbst wenn es transparent is, wird das davor gezeichnete übermalt.

Der vollständigkeit halber, hier die funktionierende Lösung.

```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;

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

@SuppressWarnings("serial")
public class GuiTest extends JFrame {

	public GuiTest() {
		setSize(400, 300);
		setVisible(true);
		
		JPanel backgroundPanel = new JPanel(){
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
				Point2D center = new Point2D.Float(getWidth() / 2, getHeight() / 3);
				float radius = Math.max(getWidth(), getHeight()) / 2;
				float[] dist = { 0.0f, 1.0f };
				Color[] colors = { Color.white, Color.blue };
				RadialGradientPaint gradientPaint = new RadialGradientPaint(center,
						radius, dist, colors);

				Graphics2D g2d = (Graphics2D) g;
				g2d.setPaint(gradientPaint);
				g2d.fillRect(0, 0, getWidth(), getHeight());

				
			}
		};
		
		JPanel middlePanel = new JPanel();
		middlePanel.setOpaque(false);
		middlePanel.add(new JButton("I am legend"));
		backgroundPanel.add(middlePanel);
		add(backgroundPanel);
	}



	public static void main(String[] args) {
		new GuiTest();
	}
}
```

Danke an alle!


----------

