DoubleBuffering im AWT - Flackern verhindern: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
 
(6 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Hast du schonmal eine Anwendung (bzw. Applet) mit einer Animation entwickelt? Damit nichts flackert und die Animation glatt abläuft, benötigen wir Doppelpufferung. Swing hat von Haus aus schon Doppelpufferung eingebaut. Falls wir aus irgendeinem Grund auf AWT zurückgreifen wollen, müssen wir die Doppelpufferung selbst programmieren. Hier ist ein kleines Beispiel (gem. Zizilamoroso). Es enthält die Klasse "PanelDoubleBuffered", welche die Doppelpufferung besorgt und die wir einfach nur erweitern müssen, wann immer wir Doppelpufferung in AWT benötigen:
+
Hast du schonmal eine Anwendung (bzw. Applet) mit einer Animation entwickelt? Damit nichts flackert und die Animation glatt abläuft, benötigen wir Doppelpufferung. Swing hat von Haus aus schon Doppelpufferung eingebaut. Falls wir aus irgendeinem Grund auf AWT zurückgreifen wollen, müssen wir die Doppelpufferung selbst programmieren. Hier ist ein kleines Beispiel (nach [http://www.codeproject.com/KB/graphics/javadoublebuffer.aspx Zizilamoroso]). Es enthält die Klasse "PanelDoubleBuffered", welche die Doppelpufferung besorgt und die wir einfach nur erweitern müssen, wann immer wir Doppelpufferung in AWT benötigen:
<code=java>/*
+
 
 +
[[Datei:doublebuffering.jpg]]
 +
 
 +
<syntaxhighlight lang="java">
 +
/*
 
  * AwtDoubleBuffered.java
 
  * AwtDoubleBuffered.java
 
  */
 
  */
 +
 
import java.applet.*;
 
import java.applet.*;
 
import java.awt.*;
 
import java.awt.*;
 +
import java.lang.reflect.*;
 +
import java.util.logging.*;
  
 
public class AwtDoubleBuffered extends Applet implements Runnable {
 
public class AwtDoubleBuffered extends Applet implements Runnable {
  
     private AnimatedPanel graphic2;
+
     private AnimatedPanel animatedPanel;
 
     private boolean running;
 
     private boolean running;
  
Zeile 19: Zeile 26:
 
                 public void run() {
 
                 public void run() {
 
                     setLayout(new BorderLayout());
 
                     setLayout(new BorderLayout());
                     graphic2 = new AnimatedPanel();
+
                     animatedPanel = new AnimatedPanel();
                     add(graphic2);
+
                     add(animatedPanel);
 
                 }
 
                 }
 
             });
 
             });
         } catch (Exception ex) {
+
         } catch (final InterruptedException ex) {
             ex.printStackTrace();
+
             Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
 +
        } catch (final InvocationTargetException ex) {
 +
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
 
         }
 
         }
 
     }
 
     }
Zeile 31: Zeile 40:
 
     public void start() {
 
     public void start() {
 
         new Thread(this).start();
 
         new Thread(this).start();
 +
    }
 +
 +
    @Override
 +
    public void stop() {
 +
        setRunning(false);
 
     }
 
     }
  
 
     public void run() {
 
     public void run() {
         running = true;
+
         setRunning(true);
         while (running) {
+
         while (isRunning()) {
             graphic2.animateToTheRight();
+
             animatedPanel.animateToTheRight();
             try {
+
             waitMilliseconds(50);
                Thread.sleep(50);
+
        }
            } catch (InterruptedException ex) {
+
    }
                ex.printStackTrace();
+
 
            }
+
    private void waitMilliseconds(final int millis) {
 +
        try {
 +
            Thread.sleep(millis);
 +
        } catch (final InterruptedException ex) {
 +
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
 
         }
 
         }
 
     }
 
     }
  
     @Override
+
     public boolean isRunning() {
     public void stop() {
+
        return running;
         running = false;
+
    }
 +
 
 +
     public void setRunning(final boolean running) {
 +
         this.running = running;
 
     }
 
     }
 
}
 
}
Zeile 53: Zeile 74:
 
class PanelDoubleBuffered extends Panel {
 
class PanelDoubleBuffered extends Panel {
  
     private int width;
+
     private int panelWidth;
     private int height;
+
     private int panelHeight;
     private Image offscreen;
+
     private Image offscreenImage;
     private Graphics graphics;
+
     private Graphics offscreenGraphics;
  
 
     public PanelDoubleBuffered() {
 
     public PanelDoubleBuffered() {
Zeile 72: Zeile 93:
 
         // checks the buffersize with the current panelsize
 
         // checks the buffersize with the current panelsize
 
         // or initialises the image with the first paint
 
         // or initialises the image with the first paint
         if (width != getSize().width ||
+
         if (panelWidth != getSize().width
                height != getSize().height ||
+
                || panelHeight != getSize().height
                offscreen == null || graphics == null) {
+
                || offscreenImage == null || offscreenGraphics == null) {
 
             resetBuffer();
 
             resetBuffer();
 
         }
 
         }
         if (graphics != null) {
+
         if (offscreenGraphics != null) {
 
             //this clears the offscreen image, not the onscreen one
 
             //this clears the offscreen image, not the onscreen one
             graphics.clearRect(0, 0, width, height);
+
             offscreenGraphics.clearRect(0, 0, panelWidth, panelHeight);
 
             //calls the paintbuffer method with
 
             //calls the paintbuffer method with
 
             //the offscreen graphics as a param
 
             //the offscreen graphics as a param
             paintBuffer(graphics);
+
             paintBuffer(offscreenGraphics);
 
             //we finaly paint the offscreen image onto the onscreen image
 
             //we finaly paint the offscreen image onto the onscreen image
             g.drawImage(offscreen, 0, 0, this);
+
             g.drawImage(offscreenImage, 0, 0, this);
 
         }
 
         }
 
     }
 
     }
Zeile 90: Zeile 111:
 
     private void resetBuffer() {
 
     private void resetBuffer() {
 
         // always keep track of the image size
 
         // always keep track of the image size
         width = getSize().width;
+
         panelWidth = getSize().width;
         height = getSize().height;
+
         panelHeight = getSize().height;
 
         // clean up the previous image
 
         // clean up the previous image
         if (graphics != null) {
+
         if (offscreenGraphics != null) {
             graphics.dispose();
+
             offscreenGraphics.dispose();
 
         }
 
         }
         if (offscreen != null) {
+
         if (offscreenImage != null) {
             offscreen.flush();
+
             offscreenImage.flush();
 
         }
 
         }
 
         // create the new image with the size of the panel
 
         // create the new image with the size of the panel
         offscreen = createImage(width, height);
+
         offscreenImage = createImage(panelWidth, panelHeight);
         graphics = offscreen.getGraphics();
+
         offscreenGraphics = offscreenImage.getGraphics();
 
     }
 
     }
  
Zeile 121: Zeile 142:
  
 
     public void animateToTheRight() {
 
     public void animateToTheRight() {
         // this can be called from everywhere, anytime
+
         // this method can be called from everywhere, anytime (thread safe)
         posX++;
+
         boolean dispatchThread = EventQueue.isDispatchThread();
         repaint();
+
        if (dispatchThread) {
 +
            int w = getWidth();
 +
            posX++;
 +
            if (posX > w) {
 +
                posX = 0;
 +
            }
 +
            repaint();
 +
         } else {
 +
            EventQueue.invokeLater(new Runnable() {
 +
 
 +
                public void run() {
 +
                    animateToTheRight();
 +
                }
 +
            });
 +
        }
 
     }
 
     }
  
     // attention: we don't touch update() and paint() anymore
+
     // ATTENTION: we don't touch update() and paint() anymore!
     // we use paintbuffer() instead
+
     // we use paintbuffer() instead:
 
     @Override
 
     @Override
 
     public void paintBuffer(final Graphics g) {
 
     public void paintBuffer(final Graphics g) {
Zeile 134: Zeile 169:
 
         g.drawString("doublebuffered", posX, 20);
 
         g.drawString("doublebuffered", posX, 20);
 
     }
 
     }
}</code=java>
+
}
[[Kategorie:Java]]
+
</syntaxhighlight>
 +
[[Kategorie:Java 2D]]
 +
[[Kategorie:AWT]]
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Java-Codeschnipsel]]
 
[[Kategorie:Java-Codeschnipsel]]

Aktuelle Version vom 22. Dezember 2018, 10:19 Uhr

Hast du schonmal eine Anwendung (bzw. Applet) mit einer Animation entwickelt? Damit nichts flackert und die Animation glatt abläuft, benötigen wir Doppelpufferung. Swing hat von Haus aus schon Doppelpufferung eingebaut. Falls wir aus irgendeinem Grund auf AWT zurückgreifen wollen, müssen wir die Doppelpufferung selbst programmieren. Hier ist ein kleines Beispiel (nach Zizilamoroso). Es enthält die Klasse "PanelDoubleBuffered", welche die Doppelpufferung besorgt und die wir einfach nur erweitern müssen, wann immer wir Doppelpufferung in AWT benötigen:

Doublebuffering.jpg

/*
 * AwtDoubleBuffered.java
 */

import java.applet.*;
import java.awt.*;
import java.lang.reflect.*;
import java.util.logging.*;

public class AwtDoubleBuffered extends Applet implements Runnable {

    private AnimatedPanel animatedPanel;
    private boolean running;

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

                public void run() {
                    setLayout(new BorderLayout());
                    animatedPanel = new AnimatedPanel();
                    add(animatedPanel);
                }
            });
        } catch (final InterruptedException ex) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
        } catch (final InvocationTargetException ex) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void start() {
        new Thread(this).start();
    }

    @Override
    public void stop() {
        setRunning(false);
    }

    public void run() {
        setRunning(true);
        while (isRunning()) {
            animatedPanel.animateToTheRight();
            waitMilliseconds(50);
        }
    }

    private void waitMilliseconds(final int millis) {
        try {
            Thread.sleep(millis);
        } catch (final InterruptedException ex) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
        }
    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(final boolean running) {
        this.running = running;
    }
}

class PanelDoubleBuffered extends Panel {

    private int panelWidth;
    private int panelHeight;
    private Image offscreenImage;
    private Graphics offscreenGraphics;

    public PanelDoubleBuffered() {
        super();
    }

    @Override
    public void update(final Graphics g) {
        paint(g);
    }

    @Override
    public void paint(final Graphics g) {
        super.paint(g);
        // checks the buffersize with the current panelsize
        // or initialises the image with the first paint
        if (panelWidth != getSize().width
                || panelHeight != getSize().height
                || offscreenImage == null || offscreenGraphics == null) {
            resetBuffer();
        }
        if (offscreenGraphics != null) {
            //this clears the offscreen image, not the onscreen one
            offscreenGraphics.clearRect(0, 0, panelWidth, panelHeight);
            //calls the paintbuffer method with
            //the offscreen graphics as a param
            paintBuffer(offscreenGraphics);
            //we finaly paint the offscreen image onto the onscreen image
            g.drawImage(offscreenImage, 0, 0, this);
        }
    }

    private void resetBuffer() {
        // always keep track of the image size
        panelWidth = getSize().width;
        panelHeight = getSize().height;
        // clean up the previous image
        if (offscreenGraphics != null) {
            offscreenGraphics.dispose();
        }
        if (offscreenImage != null) {
            offscreenImage.flush();
        }
        // create the new image with the size of the panel
        offscreenImage = createImage(panelWidth, panelHeight);
        offscreenGraphics = offscreenImage.getGraphics();
    }

    public void paintBuffer(final Graphics g) {
        // in classes extended from this one, add something to paint here!
        // always remember, g is the offscreen graphics
    }
}

class AnimatedPanel extends PanelDoubleBuffered {

    private int posX;

    public AnimatedPanel() {
        super();
        posX = 0;
        setBackground(Color.BLACK);
    }

    public void animateToTheRight() {
        // this method can be called from everywhere, anytime (thread safe)
        boolean dispatchThread = EventQueue.isDispatchThread();
        if (dispatchThread) {
            int w = getWidth();
            posX++;
            if (posX > w) {
                posX = 0;
            }
            repaint();
        } else {
            EventQueue.invokeLater(new Runnable() {

                public void run() {
                    animateToTheRight();
                }
            });
        }
    }

    // ATTENTION: we don't touch update() and paint() anymore!
    // we use paintbuffer() instead:
    @Override
    public void paintBuffer(final Graphics g) {
        // g is the offscreen graphics
        g.setColor(Color.WHITE);
        g.drawString("doublebuffered", posX, 20);
    }
}