# zeichnen auf awt canvas



## noob-1 (27. Jan 2009)

Ich möchte auf einem Canvas einige Striche Zeichnen, jedoch werden in allen Tutorials die eigentlichen Zeichenbefehle immer in in draw reingeschrieben. Das möchte ich eigentlich vermeiden, deswegen habe ich folgendes gebaut. Leider klappt das so nicht. Kann mir jemand sagen, wo ich meinen Denkfehler habe und mir sagen, wie ich das richtig machen kann? 


```
import java.awt.*;

public class zeichnen extends Canvas {

    public static void main(String[] arg) {
        Frame f = new Frame();
        zeichnen z = new zeichnen();
        f.add(z);
        f.setSize(300,300);
        f.setVisible(true);
        z.painter();
    }
    
    public void painter (){
        Graphics g = getGraphics();
        g.drawOval(300,120,100,75);
    }
}
```

ps: wenn es eine Alternative zum awt Canvas gibt, nehme ich die auch gerne.


----------



## L-ectron-X (27. Jan 2009)

Du musst schon die vorgesehenen Methoden zum Zeichnen überschreiben.
Im AWT ist das _paint()_ in Swing _paintComponent()._

_getGraphics()_ sollte nie aufgerufen werden.

Ein einfaches Beispiel:

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

public class MyFrame extends JFrame {

   public MyFrame(String title) {

      super(title);
      setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      setSize(800, 600);
      setLocationRelativeTo(null);
      
      add(new Sheet());
      
      setVisible(true);
   }

   public static void main(String[] args) {
      new MyFrame("Zeichnen");
   }
}

class Sheet extends JPanel {
   public void paintComponent(Graphics g) {
      g.drawOval(200,200,400,100);
   }
}
```


----------



## noob-1 (27. Jan 2009)

grmbl.

Aber dadurch vermische ich doch nur unnötig Anzeige und Berechnung.

Oder wie kann ich jetzt z.B. von Main aus bestimmen, welche Koordinaten die Linie haben soll. (und ich habe keine Lust für jede Funktion (draLine, DrawOval, drawIrgendwas,...) eine eigene Methode zu schreiben.

Und wenn ich getGraphics() nie aufrufen soll, wozu ist es dann da? (bin jetzt leicht verwirrt)

Aber danke für die schnelle Antwort.


----------



## Marco13 (27. Jan 2009)

Um's stark vereinfacht auszudrücken: getGraphics wird "intern" verwendet - und dort, wo es verwendet wird, wissen die Leute ganz genau, was sie tun...

Man sollte Berechnung und Zeichnen im Idealfall nicht vermischen. Im Gegenteil: In der überschriebenen paintComponent-Methode sollte ja gerade NICHT gerechnet, sondern nur gezeichnet werden. Man sollte also nicht sowas machen wie

```
void paintComponent(Graphics g)
{
    for (int x=0; x<1000; x++) 
    {
        int y = aufwändigeBerechnungDesFunktionswertes();
        g.drawLine(0,0,x,y);
    }
}
```
Stattdessen sollte man entweder die berechneten Werte speichern - GROB SKIZZIERTER Pseudocode:

```
int funktionswerte[] = ...

void berechne()
{
    for (int x=0; x<1000; x++) 
    {
        funktionswerte[x] = aufwändigeBerechnungDesFunktionswertes();
    }
}

void paintComponent(Graphics g)
{
    for (int x=0; x<1000; x++) 
    {
        g.drawLine(0,0,x,funktionswerte[x]);
    }
}
```
Oder, was in MANCHEN Fällen sinnvoll sein KANN: Das ganze in ein Bild reinmalen, und in der paintComponent nurnoch das Bild malen

```
BufferedImage image = ...

void bereiteBildVor()
{
    Graphics g = image.getGraphics(); // Auf einem BufferedImage is getGraphics OK...
    for (int x=0; x<1000; x++) 
    {
        int y = aufwändigeBerechnungDesFunktionswertes();
        g.drawLine(0,0,x,y);
    }
}

void paintComponent(Graphics g)
{
    g.drawImage(image);
}
```
Aber damit werden auch Berechnung und Zeichnung vermischt, d.h. man sollte das imho auch NICHT genau SO machen (diente nur zur Verdeutlichung der Möglichkeit, ein Image zu verwenden)


----------



## Guest (27. Jan 2009)

Marco13 hat gesagt.:
			
		

> Um's stark vereinfacht auszudrücken: getGraphics wird "intern" verwendet - und dort, wo es verwendet wird, wissen die Leute ganz genau, was sie tun...


*g* ok, DAS tue ich definitiv noch nicht 






			
				Marco13 hat gesagt.:
			
		

> Oder, was in MANCHEN Fällen sinnvoll sein KANN: Das ganze in ein Bild reinmalen, und in der paintComponent nurnoch das Bild malen
> [...]
> Aber damit werden auch Berechnung und Zeichnung vermischt, d.h. man sollte das imho auch NICHT genau SO machen (diente nur zur Verdeutlichung der Möglichkeit, ein Image zu verwenden)



Das scheint am Nähsten an dem zu sein, was ich brauche. Ist ein guter Start an dem ich weiter bauen kann. 

Vielen Dank.


----------



## André Uhres (27. Jan 2009)

1234567890


----------



## noob-1 (28. Jan 2009)

So, ich habe jetzt etwas rumgespielt, jedoch klappt es noch nicht so ganz.
Ich kann das Bild in das Canvas einkopieren, jedoch kann ich das Bild selbst scheinbar nicht bearbeiten. Zumindest kopiere ich immer nur ein leeres Bild auf das Canvas.


```
import java.awt.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class graphikTest extends Canvas {
	private static imageHandler iH = new imageHandler();

	public static void main(String[] args){
        Frame f = new Frame();
        graphikTest gT = new graphikTest();
        f.add(gT);
        f.setSize(200,200);
        f.setVisible(true);

		iH.newImage(200, 200);
		BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
		img = iH.getImage();
		Graphics g = img.getGraphics();
		g.drawLine(0, 0, 100, 100);
		iH.setImage(img);
		gT.blubb();
	}

	private void blubb (){
		repaint();
	}

	public void paint(Graphics g) {
	    g.drawLine(0, 0, 300, 300);
	    g.drawImage(iH.getImage(),0,0, null );
	}
}
```



```
import java.awt.image.BufferedImage;

public class imageHandler {
	BufferedImage imgPrototyp = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);

	public BufferedImage getImage(){
		return imgPrototyp;
	}
	
	public void setImage(BufferedImage img){
		this.imgPrototyp = img;		
	}

	public void newImage(int x, int y){
		this.imgPrototyp = new BufferedImage(x,y, BufferedImage.TYPE_INT_ARGB);
	}
}
```


----------



## Quaxli (28. Jan 2009)

Du hast mit diesem komschen ImageHandler, der auch nich konventionsgemäß benannt wurde ganz schönes Durcheinander gemacht.

Erst erzeugst Du ein Image mit dem IH, dann ein BufferedImage.
Dann weist Du dem img das Bild aus dem IH zu, um dann nach einigen Zeichenoperation nochmal das setImage des IH aufzrufen. 
Das sieht nicht wirklich so aus, als ob Du weist was Du tust 

Hier mal ein lauffähiges Beispiel ohne Kapselung im ImageHandler. Schau Dir mal an, was gemacht wird und wenn Du das verstehst, probier es nochmal mit Kapselung im ImageHandler:


```
import java.awt.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

// Klassennamen schreibt man groß
public class GraphikTest extends Canvas {

	private static final long	serialVersionUID	= 1L;

	BufferedImage							img;

	public static void main(String[] args) {
		new GraphikTest();
	}
	
	public GraphikTest(){
		Frame f = new Frame();
		f.setSize(300, 300);
		this.setPreferredSize(new Dimension(300,300));
		f.add(this);

		
		img = new BufferedImage(300, 300, BufferedImage.OPAQUE); //Größe 1,1 war nicht gerade ideal
		Graphics gimg = img.createGraphics(); //createGraphics Verwenden
		gimg.setColor(Color.RED);
		gimg.drawLine(20,0, 300,300);
		gimg.dispose();
		
		f.pack();
		f.setVisible(true); //setVisible zuletzt oder repaint, wie Du's vorher hattest
	}


	public void paint(Graphics g) {
		super.paint(g); //super-Aufruf nicht vergessen
		g.drawImage(img, 0, 0, null);
		g.setColor(Color.BLUE);
		g.drawLine(0, 0, 300, 300);
		g.dispose();
	}
}
```


----------



## Ebenius (28. Jan 2009)

Quaxli hat gesagt.:
			
		

> ```
> public void paint(Graphics g) {
> super.paint(g); //super-Aufruf nicht vergessen
> g.drawImage(img, 0, 0, null);
> ...


Genau hier ist Graphics.dispose() falsch! Dispose macht man immer dann, wenn man selbst ein Graphics-Objekt erstellt; zum Beispiel per Graphics.create(). Ein Graphics-Objekt, welches Du nur geliehen bekommst, zerstörst Du nicht. Warum nicht? Leite doch einfach nochmal von GraphikTest ab und versuch noch was obendrauf zu zeichnen. Klar?


----------



## Quaxli (28. Jan 2009)

Stimmt. Danke für die Korrektur. 
Zwar wird diese Klasse wohl nicht mehr vererbt, aber man sollte sich sowas doch gar nicht erst angewöhnen.


----------

