# Java Applet - Double Buffering Problem (Flackern)



## event_horizon (23. Mrz 2009)

Hallo zusammen,

naachdem ich zum Double Buffering schon Einiges gelesen habe und auch probiert habe, hier mein Problem:

Benutze ein Java Applet mit einem Image der Größe 640x480 bzw. noch ein wenig größer, da noch Click Areas dabei sind die je nachdem welche angeklickt wird im Applet etwas Bestimmtes anzeigen (jetzt noch eher Sinnloses, später hoffentlich schöne Graphiken). Das Applet ist noch um den Rand (2 Pixel) größer. Soweit so gut. Ich löse das Ganze mit einem Thread und benutze zwei Images und zwei Graphics zum "doppelten" Double Buffering (hab das mal so als Beispiel bekommen)

Also in etwa so:

[highlight=Java]
public void init ()
{


  buffer1 = createImage(640, 500);
  graph1 = buffer1.getGraphics();

  buffer2 = createImage(640, 500);
  graph2 = buffer2.getGraphics();

  setBackground(Color.black);

[/highlight]

Thread:
[highlight=Java]
public void start()
    {

        if(t == null)
        {

            t = new Thread(this);
            threadAussetzen = false;
            t.start();
        }
        else
        {

            if(threadAussetzen)
            {

                threadAussetzen = false;

                synchronized(this)
                {
                    notify();
                }
            }
        }
    }

[/highlight]

Im Stop wird threadAussetzen = true gesetzt.

Im run des Threads wird dann neben Synchronisierung Folgendes gemacht:

[highlight=Java]

Graphics g;

if(schalter == 0)
 {
     g = backg2;
  }

   else
   {
      g = backg1;
    } // end else

    g.setColor(getBackground());
    g.fillRect(0,0,640,500);
    g.setColor(Color.white);


      if (!clickedArea1 && !clickedArea2)
      {
         g.drawString("bla bla!", 160,240);
      }

      else
      {
         if (clickedArea1)
         {
             g.drawString("bla bla 1!", 160,240);
         }

         else
         {
            g.drawString("bla bla 2!", 160,240);
         }
      }

     g.drawLine(x1,y1,x2,y2);

    // Ein paar mehr Linien werden noch gezeichnet

     schalter ^= 1;
     repaint();

[/highlight]

update und paint sehen so aus:

[highlight=Java]
public void update(Graphics g)
    {

        if(schalter == 0)
        {
            g.drawImage(buffer1, 2, 2, this);
        }

        else
        {
            g.drawImage(buffer2, 2, 2, this);
        } 
    }

    public void paint(Graphics g)
    {
        //
        // Update the window.
        //
        update(g);
    }

[/highlight]

Jetzt meine Fragen (ok, dass ich kein Java Guru bin, hat man sicher am Code gemerkt):

Wieso flackert das immer noch?
Was kann man dagegen machen?
Gibts Probleme beim Buffering?
Ist das Image einfach zu groß?

Ok, war wirklich lange. Danke schon mal im Voraus fürs Feedback.

LG

EH


----------



## André Uhres (23. Mrz 2009)

event_horizon hat gesagt.:


> nachdem ich zum Double Buffering schon Einiges gelesen habe und auch probiert habe, hier mein Problem:


Warum nimmst du nicht einfach Swing? Eine der bemerkenswertesten Eigenschaften von Swing ist, daß es die Unterstützung für Doppelpufferung direkt ins Toolkit einbaut. Beispiel:

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

public class AppletTest extends JApplet {

    private boolean clickedArea1;
    private boolean clickedArea2;
    private int x1 = 50,  y1 = 50,  x2 = 200,  y2 = 200;

    /** Initializes the applet AppletTest */
    @Override
    public void init() {
        try {
            EventQueue.invokeAndWait(new Runnable() {

                public void run() {
                    add(new Graphic());
                }
            });
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    class Graphic extends JComponent {

        public Graphic() {
            setBackground(Color.black);
        }

        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.setColor(getBackground());
            g.fillRect(0, 0, 640, 500);
            g.setColor(Color.white);
            if (!clickedArea1 && !clickedArea2) {
                g.drawString("bla bla!", 160, 240);
            } else {
                if (clickedArea1) {
                    g.drawString("bla bla 1!", 160, 240);
                } else {
                    g.drawString("bla bla 2!", 160, 240);
                }
            }
            g.drawLine(x1, y1, x2, y2);
        // Ein paar mehr Linien werden noch gezeichnet
        }
    }
}
```


----------



## event_horizon (23. Mrz 2009)

Danke mal für die Antwort. Von Swing habe ich schon mal was gehört, aber noch nie was damit gemacht. Ich kann's ja mal ausprobieren.

Mich würde trotzdem interessieren, warum meine Implementierung flackert, einfach, um es zu verstehen und etwas dazuzulernen.

EDIT: Wenn ich das Applet im Browser laufen lasse, ist die CPU fast völlig ausgelastet. Hmm, ist ja auch nicht gerade im Sinne des Erfinders


----------



## André Uhres (24. Mrz 2009)

event_horizon hat gesagt.:


> Mich würde trotzdem interessieren, warum meine Implementierung flackert


Im Code, den du uns gezeigt hast, ist alles statisch. Es kann nichts flackern. Am besten machst du ein kurzes, selbständiges und kompilierbares Beispiel. Wenn du willst, kannst du auch mit folgendem Beispiel vergleichen: AwtDoubleBuffered - Byte-Welt Wiki


----------



## event_horizon (24. Mrz 2009)

André Uhres hat gesagt.:


> Im Code, den du uns gezeigt hast, ist alles statisch. Es kann nichts flackern. Am besten machst du ein kurzes, selbständiges und kompilierbares Beispiel. Wenn du willst, kannst du auch mit folgendem Beispiel vergleichen: AwtDoubleBuffered - Byte-Welt Wiki


 
Hmmm, wenn ich keinen Text verwende, sondern nur irgendwelche Muster zeichne - also Graphic Area Pixel für Pixel aufbaue bzw. ein paar Flächen anmale - dann flackert es nicht. Woran kann das liegen?


----------



## L-ectron-X (24. Mrz 2009)

Es kann schon flackern. Das Konzept stimmt nicht.
Der Aufruf von update() gehört nicht in die paint()-Methode.

Beim DoubleBuffering wird, so wie ich es kenne, die Hauptarbeit in der update()-Methode gemacht, die von Hause aus leer ist und mit sinnvollem Code gefüllt werden muss.

Hier mal ein Beispiel, wie man es besser machen kann.
Zumindest ist der Code für das DoubleBuffering OK.
http://www.java-forum.org/deployment/28009-mouseentered-mit-einem-bild-im-applet.html#post179043


----------



## André Uhres (24. Mrz 2009)

L-ectron-X hat gesagt.:


> Beim DoubleBuffering wird, so wie ich es kenne, die Hauptarbeit in der update()-Methode gemacht, die von Hause aus leer ist und mit sinnvollem Code gefüllt werden muss.


AWT ruft für heavyweight Komponenten bei einem systemausgelöster Malvorgang die update Methode nicht auf. Daher gehört die Hauptarbeit wohl eher in die paint Methode.

Wenn die Komponente nicht update() überschreibt, löscht die Default-Implementierung von update() den Hintergrund der Komponente (wenn es nicht eine lightweight Komponente ist) und ruft einfach paint() auf. 

Während es zutreffend ist, daß die Default-Implementierung von update() die paint() aufruft, ermöglicht dieser "Updatehaken" einem Programm, den anwendungsausgelösten Malvorgang anders anzufassen, wenn es gewünscht wird. Ein Programm muß annehmen, daß ein Aufruf von paint() andeutet, daß der Bereich, der durch das Cliprechteck vom Graphics definiert wird, "beschädigt" ist und vollständig neu gezeichnet werden muß, gleichwohl ein Aufruf von update() dieses nicht andeutet, was einem Programm ermöglicht, zusätzliches Zeichnen zu tun.

Zusätzliches Zeichnen* ("incremental painting") ist nützlich, wenn ein Programm die zusätzliche Darstellung über die vorhandenen Teilstücke dieser Komponente überlagern möchte. Dadurch kann auch ein Flackern verhindert werden. Siehe auch: Malen in AWT und Swing - Byte-Welt Wiki

Das Konzept der Doppelpufferung ist aber noch ein anderes. Die Idee dahinter ist, dass wir zuerst alles auf ein off-screen Image malen, und, wenn's fertig ist, das off-screen Image mit einem einzigen drawImage auf die on-screen Graphics kopieren.

*ANMERKUNG: beachte bitte, daß die zusätzliche Zeichnentechnik (incremental painting) nicht für lightweight Komponenten verwendet werden sollte.


----------

