# Auf JPanel zeichnen



## michi2 (20. Aug 2006)

Hallo,
Hier hatt man mit nahegelegt das ich die Canvas/JPanel neuschreiben soll und das ich mir die dazugehörigen Grundlagen in Tutorials und diesem Forum suchen soll. Allerdings find ich dazu absolut nix (bin wohl zu blöd zum suchen).
Habt ihr Links?

Ich weiß das gehört eigentlich ins Tut.-Forum, aber es ist ja kein Link auf ein Tut sondern eine Frage... und ins Tut-Forum schauen weniger Leute...


----------



## michaelb (20. Aug 2006)

Hi,
also hier gibt's was:
http://java.sun.com/docs/books/tutorial/uiswing/14painting/index.html
und hier hab ich ein kleines Beispiel mal gepostet:
http://www.java-forum.org/de/viewtopic.php?p=214352&highlight=#214352
Gruß Michi


----------



## André Uhres (21. Aug 2006)

http://www.java-forum.org/de/viewtopic.php?p=145317#145317
http://forum.java.sun.com/thread.jspa?forumID=57&threadID=607073


----------



## michi2 (21. Aug 2006)

Also, ich versteh das noch nicht wirklich:
Wie soll ich zeichnen wen ich getGraphics() nicht aufrufen darf?


----------



## michi2 (21. Aug 2006)

Währe folgendes in Ordnung?


```
class CMeineCanvas extends JPanel
   {
   CMeineCanvas()
      {
      setBackground(Color.black);	// den Hintergrund auf schwarz setzen
      setForeground(Color.green);	// Vordergrund (=ZeichenFarbe) auf blau setzen
      }
   public void paintComponent(Graphics g)
      {
      super.paintComponent(g);
      g.drawImage(Image img, 0, 0, observer);
      }

   
   //Zeichnet einen Wert
   void paintValue(int xpos, int ypos)
      {
      img.getGraphics().fillOval(xpos,ypos,1,1);	//Ein Oval zeichnen
      repaint();
      }


   
   // Diese Methode liefert die minimale Größe der Canvas
   public Dimension getMinimumSize()
      {
      return CFunkPlotter2.FP.di;
      }
   
   // Die Lieblingsgröße setzen wir auf die Minimalgröße
   public Dimension getPreferredSize()
      {
      return getMinimumSize();
      //return new Dimension(3*getToolkit().getScreenResolution(),3*getToolkit().getScreenResolution());
      }
   }//Ende CMeineCanvas
```

Würde doch immer alles löschen was auf der JPanel ist wenn paintValue() aufgerufen wird, oder?


Michi


----------



## michi2 (21. Aug 2006)

Könntet ihr mir bitte das ein wenig erklären, die Anleitungen die ihr mir gebt wiedersprechen zimlich den Regeln die Wildcard mir hier gegeben hat.


----------



## Beni (21. Aug 2006)

Wildcard hat in allen Punkten recht, nur etwas könnte man noch hinzufügen: das Graphics darf man von einer Methoden in die nächste reichen.

Im übrigen hat dein Quellcode Syntaxfehler, und kann deshalb nicht richtig sein :wink:

Grundsätzlich zeichnet man mit Swing immer etwa so:

```
public class X extends JPanel{
  // paintComponent überschreiben
  public void paintComponent( Graphics g ){
    super.paintComponent( g ); 

    // entweder direkt was in der Methode zeichnen
    g.setColor( Color.RED );
    g.fillOval( 0, 0, getWidth(), getHeight() );

    // oder an eine andere Methode delegieren
    paintSomething( g );
  }

  private void paintSomething( Graphics g ){
    g.setColor( Color.GREEN );
    g.drawRect( 17, 18, 42, 47 );
  }
}
```

Manchmal ist das Bild das man haben will aber sehr kompliziert. Da "paintComponent" nur wenige Millisekunden Zeit hat, etwas auf den Bildschirm zu zaubern, muss man im vorraus arbeiten. Das macht man dann mit einem Image.

Etwa so:

```
public class Y extends JPanel{
  private BufferedImage image;

  public void paintComponent( Graphics g ){
    super.paintComponent( g );
    // Das Bild zeichnen wir nur, wenn es auch existiert....
    if( image != null )
      g.drawImage( image, 0, 0, this );
  }

  // Die Methode rufen wir "zu einem geeigneten Zeitpunkt" auf.
  // Zum Beispiel wenn wir neue Daten kennen, oder irgendwie
  // wissen, dass das Bild jetzt anders aussehen muss.
  // Die Methode könnten wir aus einem "actionPerformed" aufrufen...
  public void createTheFancyImage(){
    // das Bild mit der richtigen Grösse erzeugen...    
    image = new BufferedImage( ... );
 
    // Grahpics des Bildes holen, um auf das Bild zu zeichnen
    Graphics imgG = image.getGraphics(); 

    imgG.setColor( Color.RED );

    ... // hier ein paar 1000 Methodenaufrufe

    repaint();
  }
}
```

Ansonsten muss ich leider sagen, ich versteh dein Problem nicht. Wie schon meine Vorredner sagten, im Netz gibt es 1000 Beispiele...


----------



## michi2 (22. Aug 2006)

OK, danke das hiltf mir weiter!



> Ansonsten muss ich leider sagen, ich versteh dein Problem nicht. Wie schon meine Vorredner sagten, im Netz gibt es 1000 Beispiele...


Alerdings scheinen die gut verstekt zu sein  Google und Co finden nix... Oder nach was muss ich da suchen? ("JPanel paint", "JPanel zeichen" und a bringen nix)


----------



## Gast (22. Aug 2006)

Also wenn du auf ein JPanel zeichnen willst, dann mach das so:

überschreibe die paintComponent(...) Methode zb so:

public void paintComponent(Graphics g){




		super.paintComponent(g);

		Graphics2D g2d = (Graphics2D) g.create();
		// fuer schoene Kanten
		Graphics2D g2 = g2d;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

g2d.dispose();

}

alles was du zeichnen willst muss vor g2d.dispose() stehen.

wenn du zeichnen willst, kannste das mit g2d.... machen

zb. g2d.drawString("hallo",50,50);
g2d.setColor(...)
g2d.drawLine(...)


----------



## michi2 (22. Aug 2006)

Ok, hab das jetzt auf dieser Grundlage neu geschrieben.
Ist das so in Ordnung?

```
package plotter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import java.math.*;


class CMeineCanvas extends JPanel
   {
   NLogCoordinateSystem notLogSys;
   SLogCoordinateSystem simpleLogSys;
   DLogCoordinateSystem dualLogSys;
   private BufferedImage image; 
   
   CMeineCanvas()
      {
      setBackground(Color.black);	// den Hintergrund auf schwarz setzen
      setForeground(Color.green);	// Vordergrund (=ZeichenFarbe) auf grün setzen
      }
   
   public void paintComponent( Graphics g )
      {
      super.paintComponent( g );
      // Das Bild zeichnen wir nur, wenn es existiert
      if( image != null )
         g.drawImage( image, 0, 0, this );
      } 
   
   
   // Die wichtigste Methode: hier wird gezeichnet!
   public void paintfunk()
      {
      //Die Farbe wird aus einem Array genomen, w ist der Zähler
      int w = CFunkPlotter2.FP.w;
      w++;
      if(w>CFunkPlotter2.FP.Farbe.length-1)
         {
         w=0;
         }
      if(image==null)
         image = new BufferedImage((int) getMinimumSize().getWidth(),
      (int) getMinimumSize().getHeight(), BufferedImage.TYPE_INT_RGB);
      Graphics g = image.getGraphics();	//Graphics erzeugen
      
      //Über prüfen ob die alte Funktion erhalten werden soll, wenn nicht -> löschen
      if(!CFunkPlotter2.FP.cb1.isSelected())
         {
         g.clearRect(0,0,(int) CFunkPlotter2.FP.di.getWidth(),(int) CFunkPlotter2.FP.di.getHeight());
         CFunkPlotter2.FP.werte.setText("");
         w=0;
         }
      
      //Es wird überprüft welcher Typ von Koordinatensystem verwendet werden soll
      switch ( CFunkPlotter2.FP.CoordinateType)
         {
         case 'n':	//n: not (LogarithmikCoordinateSystem)
         notLogSys = new NLogCoordinateSystem( CFunkPlotter2.FP, w);
         g = notLogSys.paintCoordinateSystem(g);
         break;
         
         case 's':	//s: simpel (LogarithmikCoordinateSystem)
         simpleLogSys = new SLogCoordinateSystem( CFunkPlotter2.FP, w);
         g = simpleLogSys.paintCoordinateSystem(g);
         break;
         
         case 'd':	//d: double (LogarithmikCoordinateSystem)
         dualLogSys = new DLogCoordinateSystem( CFunkPlotter2.FP, w);
         g = dualLogSys.paintCoordinateSystem(g);
         break;
         
         default:
         System.out.println("Es scheint das sich hier ein Fehler eingeschlichen hat.\n Bitte informieren sie mich: über [url]http://www.schoenitzer.de\n[/url] Vielen Dank!");
         }
      
      // Wenn keine Funktion ausgewählt ist, nichts tun
      if( CFunkPlotter2.FP.aktFunktion == 0)
         return;
      
      //Parameter abfragen
      double[] para = CFunkPlotter2.FP.getParams();
      if(para == null)
         return;
      
      // Die Funktion generieren
      Funk f = new Funk(para);
      f.funk =  CFunkPlotter2.FP.aktFunktion;
      
      //Eintragen der Beschreibung der Funktion und des Schnittpunktes mit der  y-Achse in die Info-box
      CFunkPlotter2.FP.werte.append(f.beschreibung()+"\n");
      if(!Double.isNaN(f.yWert(0)) && !Double.isInfinite(f.yWert(0)))
         CFunkPlotter2.FP.werte.append("Schnittpunkt mit der y-Achse bei y = "+Math.rint(f.yWert(0)*1000)/1000+"\n");
      else
      CFunkPlotter2.FP.werte.append("Kein Schnittpunkt mit der y-Achse!\n");
      
      
      //Es wird überprüft welcher Typ von Koordinatensystem verwendet werden soll (siehe oben)
      switch ( CFunkPlotter2.FP.CoordinateType)
         {
         case 'n':
         notLogSys.paintFunk(f);
         break;
         
         case 's':
         simpleLogSys.paintFunk(f);
         break;
         
         case 'd':
         dualLogSys.paintFunk(f);
         break;
         
         default:
         System.out.println("Es scheint das sich hier ein Fehler eingeschlichen hat.\n Bitte informieren sie mich: über [url]http://www.schoenitzer.de\n[/url] Vielen Dank!");
         }
      CFunkPlotter2.FP.w = w;
      repaint();		//###Nötig?
      }
   
   //Zeichnet einen Wert
   void paintValue(int xpos, int ypos, Color paintingC)
      {
      Graphics gr = image.getGraphics();
      gr.setColor(paintingC);
      gr.fillOval(xpos,ypos,1,1);	//Ein Oval zeichnen
      repaint();		//n: not (LogarithmikCoordinateSystem)
      }      
   
   
   // Diese Methode liefert die minimale Größe der Canvas
   public Dimension getMinimumSize()
      {
      return CFunkPlotter2.FP.di;
      }
   
   // Die Lieblingsgröße setzen wir auf die Minimalgröße
   public Dimension getPreferredSize()
      {
      return getMinimumSize();
      //return new Dimension(3*getToolkit().getScreenResolution(),3*getToolkit().getScreenResolution());
      }
   }//Ende CMeineCanvas
```


----------



## Wildcard (22. Aug 2006)

@Gast
Warum denn ein neues Graphics Objekt?


----------



## michi2 (22. Aug 2006)

Servus Wildcard, das komische Problem, durch das du mich erst auf das gebracht hast besteht übrigens weiterhin... Glaub aber das ich's lösen kann, wenn nicht werd ich nochmal fragen...

Hoffe ich geh euch nicht al zu sehr auf die Nerven


----------



## Guest (22. Aug 2006)

Wildcard hat gesagt.:
			
		

> @Gast
> Warum denn ein neues Graphics Objekt?



dann habe ich ein Graphics2D Objekt und kann damit schöner zeichnen. Kantenglättung und sowas is auch drin.

oder lieg ich da falsch?


----------



## Wildcard (22. Aug 2006)

Das übergebene Graphics Objekt ist bereits ein Graphics2D. Einfach casten  :wink:


----------



## Guest (22. Aug 2006)

Wildcard hat gesagt.:
			
		

> Das übergebene Graphics Objekt ist bereits ein Graphics2D. Einfach casten  :wink:



tja wieder was gelernt  

Hatte das vor ner ganzen Weile mal so ausm Internet und immer so benutzt


----------



## michi2 (22. Aug 2006)

Irgentwas gegen meinen Code? Kann ich in so benützen?


----------



## Beni (22. Aug 2006)

Für mich sieht das brauchbar aus.

Wenn du dein Panel in einem (J)Frame hast, und du das Frame minimierst, und anschliessend wieder vergrössern, *und dann* das Bild noch da ist - dann hast du alles richtig gemacht.


----------



## michi2 (22. Aug 2006)

Ja, hällt bei mir allen tests stand.
Nach deinem Beispiel war das umschreiben/neuschreiben garnicht viel Arbeit! Solltest wenn du Lust hast, das vielleicht in die FAQ herfen.


----------

