Bitmap produzieren

Ich habe ein Programm dort zeichne ich bisher bei jedem aufruf von paint(Graphics g) den Hintergrund neu, da dauert natürlich etwas, dann kommen die sachen dazu die sich verändern.Jetzt möchteich das gezeichnet Hintergrundbild gerne als Image speichern.
Beim nächsten Aufruf von paint(Graphics g) soll dann zuerst das Image geladen werden und die neue Grafik dann gezeichnet werden.

Ich habe bisher es mit einer abgeänderten Version der update(Graphics g) Methode versucht die in Zahlreichen Büchern verwendet wird um das „Flackern“ zu verhindern, doch das klappte nicht.

Könnt ihr mir helfen?

Danke, Wizard of War

Moin

Beim nächsten Aufruf von paint(Graphics g) soll dann zuerst
das Image geladen werden und die neue Grafik dann gezeichnet
werden.

Also eine art 2x doublebuffer:

Image hintergrund = java.awt.Component.createImage(int width, int height)

Graphics g = hintergrund.getGraphics();

… auf g dein Hintergrund malen …

bei paint mit g.drawImage(hintergrund…) arbeiten.

cu

Es klappt noch nicht ganz:
Also ich habe jetzt ein Image am Programmstart definiert.
Dann habe ich eine Methode Hintergrundmalen:

public void hintergrundMalen()
{
Image hintergrundBild = java.awt.Component.createImage(bildBreite, bildHöhe);
Graphics g = hintergrundBild.getGraphics();
// male, male
}
Und in Paint folgt der aufruf:

public void paint(Graphics g)
{
g.drawImage(hintergrundbild,x, y,this);
}

Dummerweise kommt dann immer folgender Fehler:
non-static method createImage(Int, Int) cannot be referenced from a static context

Auch wenn ich das Image in der Methode hintergrundmalen erst erzeuge, und dann übergebe selbst dann kommt der Fehler…

Moin

Dummerweise kommt dann immer folgender Fehler:
non-static method createImage(Int, Int) cannot be referenced
from a static context

Ja, klar, die Methode ist ja auch nicht statisch. Man ruft createImage auf dem Object auf desen Hintergrund es werden soll. Also:

public class myCanvas extends java.awt.Canvas{

 private Image hintergrund;

 public paint (Graphics g){
 boolean newHintergrund = false;
 if (hintergrund==null){
 hintergrund = this.createImage (this.getWidth(),this.getHeight());
 newHintergrund = true;
 }
 if ((hintergrund.getWidth(this)!=this.getWidth()) || hintergrund.getHeight(this)!=this.getHeight())){
 hintergrund.flush();
 hintergrund = null;
 hintergrund = this.createImage (this.getWidth(),this.getHeight());
 newHintergrund = true;
 }
 if (newHintergrund){
 //zeug reinmalen
 }
 g.drawImage (newHintergrund,...);

 //rest malen.
 }
}

Und denk ans doublebuffering …

Auch wenn ich das Image in der Methode hintergrundmalen erst
erzeuge, und dann übergebe selbst dann kommt der Fehler…

? erklär den Punkt nochmal ?

cu

klappt immer noch nicht
Ich poste hier mal meinen/deinen Quellcode:

public class Karte extends Applet implements MouseListener
{
 Image dbImage, hintergrund;
 Graphics dbGraphics;

 public void paint(Graphics g)
 {
 boolean newHintergrund = false;
 if (hintergrund==null){
 hintergrund = this.createImage(this.getWidth(),this.getHeight());
 newHintergrund = true;
 }
 if ((hintergrund.getWidth(this)!=this.getWidth()) || (hintergrund.getHeight(this)!=this.getHeight())){
 hintergrund.flush();
 hintergrund = null;
 hintergrund = this.createImage(this.getWidth(),this.getHeight());
 newHintergrund = true;
 }
 if (newHintergrund){
 //zeug reinmalen
 g.setColor(Color.black);
 g.drawLine(3,3,19,19);
 System.out.println("Hintergrund fertig");
 }

 g.drawImage (hintergrund,50,50,this);
 g.fillRect(30,30,10,10);
 System.out.println("repaint");
 }

 public void mousePressed(MouseEvent e)
 {
 repaint();
 }
 public void mouseReleased(MouseEvent e)
 {}
 public void mouseEntered(MouseEvent e)
 {}
 public void mouseExited(MouseEvent e)
 {}
 public void mouseClicked(MouseEvent e)
 {}
}

Theoretisch sollte die Linie ja bei 53,53 anfangen und bei 69,69 aufhören, doch sie erscheint bei 3,3 -> 19,19.
Fazit, das die Aktionen die eigentlich im Hintergrundbild erscheinen sollen werden sofort gezeichnet, aber nur beim ersten Start.
Übrigens verstehe ich auch die ersten bei IF-Anweisungen nicht. Reicht nicht einfach:
boolean Hintergrundvorhanden = false;
public void paint(Graphics g){
If(!Hintergrundvorhanden){
hintergrund = this.createImage(23,23);
Hintergrundvorhanden = true;
}
g.drawImage (hintergrund,50,50,this);
}

Aber auch das klappt nicht.

Wenn es dann mal funktioniert möchte ich auch gerne, dass das Hintergrundbild gleichzeitig aufm Bildschirm aufgebaut wird, während es als Image gespeichert wird, damit ich sehe wie weit das Bild ist…

Eine andere Idee:
Kann man nicht erstmal was normal zeichnen, und dann wird alles was aufm Bildschirm ist gespeichert, als Screenshot sozusagen, wobei nicht der ganze Bildschirm benötigt wird sondern nur ein Ausschnitt.

Hallo

Du hast auch erst vor kurzen mit java angefangen, oder ?

         if (newHintergrund){
            //zeug reinmalen
             g.setColor(Color.black);
             g.drawLine(3,3,19,19);
             System.out.println("Hintergrund fertig");
         }

Du benutzt das g aus „public void paint( g )“. Das Graphics-Object g gehört zum Bildschirm, und alles was man darauf zeichnet wird auf dem Bildschirm erschienen. Du willst die Linie auf das Bild „hintergrund“ malen. Deshalb:

         if (newHintergrund){
         //zeug reinmalen
             Graphics g\_hintergrund = hintergrund.getGraphics();
             g\_hintergrund.setColor(Color.black);
             g\_hintergrund.drawLine(3,3,19,19);
         }

Dann hast du ein Bild mit einer Linie bei 3,3-19,19.

Übrigens verstehe ich auch die ersten bei IF-Anweisungen nicht.
Reicht nicht einfach:

(…)

nein, da malst du ja gar nichts auf das Hintergrundbild.

Die If-Abfragen sollen 2 Fälle abfangen:

  1. Es ist der allererste Aufruf von paint() und das Image gibts noch gar nicht.

  2. Die Grösse des Applet hat sich geändert und das Image muss an die neue Grösse angepasst werden.

Wenn es dann mal funktioniert möchte ich auch gerne, dass das
Hintergrundbild gleichzeitig aufm Bildschirm aufgebaut wird,
während es als Image gespeichert wird, damit ich sehe wie weit
das Bild ist…

Dann musst du alle Graphics-Operationen auf beiden Graphics-Objecten durchführen. Ist unnötig, aber möglich.

Kann man nicht erstmal was normal zeichnen, und dann wird alles
was aufm Bildschirm ist gespeichert, als Screenshot sozusagen,
wobei nicht der ganze Bildschirm benötigt wird sondern nur ein
Ausschnitt.

Man kann aus Applets herraus den Bildschirminhalt nicht mehr zurücklesen. Pech gehabt. (Das ist ausserdem viel langsamer als der andere Weg)

cu

Habs endlich gelöst

Hallo

Du hast auch erst vor kurzen mit java angefangen, oder ?

Wie darf ich das verstehen? Auch?
Eigentlich bereits seit 1 - 1.5 Jahre aber eher selten, immer mal schubweise :wink:

Ich habe deine ersten beiden Vorschläge kombiniert und nun funzt es, bis auf die Tatsache, daß das Bild im Hintergrund aufgebaut wird.

Hier meine Lösung:

 Image dbImage, hintergrund;
 Graphics dbGraphics;
 boolean hg = false;

 public void hintergrundMalen(){
 hintergrund = this.createImage (50,50);
 Graphics g = hintergrund.getGraphics();
 g.drawLine(3,3,19,19);
 hg = true;
 }
 public void paint(Graphics g)
 {
 if(!hg)
 hintergrundMalen();
 g.drawImage (hintergrund,50,50,this);
 System.out.println("repaint");
 }

Vielen Dank für deine Hilfe!!!

Aber nochmal zu dem gleichzeitig auf dem Bildschirm zeichnen, hast du ne Idee?

Aber nochmal zu dem gleichzeitig auf dem Bildschirm zeichnen,
hast du ne Idee?

Manchmal hab ich echt ne lange Leitung…
Also ich versuche jetzt einmal mit Graphics g und Graphics g2 und zeichne das Hintergrundbild gleichzeitig auf g und g2.

Aus unerfindlichen Gründen klappt das aber nicht, es fängt an zu zeichnen aber hört wieder auf, dann bleibt der Bildschirm so bis alles komplett fertig im hintergrund gezeichnet wurde und zeigt es dann an. Keine Ahnung wieso…

Moin

Aber nochmal zu dem gleichzeitig auf dem Bildschirm zeichnen,
hast du ne Idee?

        Image dbImage, hintergrund;
        boolean hg = false;

        public void hintergrundMalen(Graphics g2){
                hintergrund = this.createImage (50,50);
                Graphics g = hintergrund.getGraphics();
                g.drawLine(3,3,19,19); //auf das Hintergrundbild
                g2.drawLine(3,3,19,19);  //auf den Bildschirm
                hg = true;
        }
     public void paint(Graphics g)
     {
       //das ist ein bisschen falsch:
        //if(!hg) 
        //      hintergrundMalen(g);
        //      g.drawImage (hintergrund,50,50,this);
       //       System.out.println("repaint");
        //}
        //richtiger wäre:
        if(!hg) 
                hintergrundMalen(g);
                System.out.println("Hintergrund aufgebaut");
        }
        System.out.println("benutze Hintergrund");
        g.drawImage (hintergrund,50,50,this);
        System.out.println("paint abgeschlossen");
     {
 

Du willst doch das Hintergrund-Bild mehrmals verwenden, oder ? In deiner Variante bleibt sonst das Applet beim 2x malen leer.

Wenn du jetzt noch die 50,50 in der Zeile „g2.drawLine(3,3,19,19);“ draufaddierst kommt die Kopie und das Bild an die gleiche Stelle.

cu

Moin

Aus unerfindlichen Gründen klappt das aber nicht, es fängt an
zu zeichnen aber hört wieder auf, dann bleibt der Bildschirm
so bis alles komplett fertig im hintergrund gezeichnet wurde
und zeigt es dann an. Keine Ahnung wieso…

Dein Applet läuft mit eingeschaltetem Doublebuffering. Schalt das aus, dann sieht man’s. (Ich weiss allerdings gerade nicht wie die Methode heist…)

cu

Nee, lag nicht am Zeichnen sondern, die Routine wurde gar nicht erreicht.
Das läuft jetz alles wunderbar, habe mich dann aber gegen einen gleichzeitiges Zeichnen entschieden, die Datenbankabfrage würde einfach zu lange dauern.
Ich habe jetzt einfach einen Fortschrittsbalken der gemalt wird.

Aber mit der Datenbank hab ich noch ein Problem dazu mehr im neuen Thread.

Danke nochmal für deine tatkräftige Hilfe!!!
Wizard of War