Search code examples
javaappletdoublebuffered

I need help understanding how to write the code for double buffering in java applets


I understand the logic behind it, but don't know how to translate that to code. Could someone please show me on this example that I wrote?

All the applet does is that the center rectangle moves up, down, right and left of its own accord. I want to get rid of the annoying flicker with a double buffer, but I don't know what change/add to make that happen.

import java.applet.*;

import java.awt.*;

public class Broadway extends Applet implements Runnable {

Thread animation;

int locx,locy; // location of rectangle
int width, height; // dimensions of rectangle

// direction of motion
static final byte UP = 0; 
static final byte DOWN = 1;
static final byte LEFT = 2;
static final byte RIGHT = 3;

byte state; // state the rect is in

// length of pausing interval in ms
static final int REFRESH_RATE = 100;


public void init() {

    setBackground(Color.black);

    locx = 80; // parameters of center rect
    locy = 100;
    width = 110;
    height = 90;
    state = UP;
}

public void start() {

    animation = new Thread(this);

    if (animation != null) {
    animation.start();
    }
}

public void paint(Graphics g) {

    g.setColor(Color.yellow);
    g.fillRect(0,0,90,90);
    g.fillRect(250,0,40,190);
    g.fillRect(80,110,100,20);

    g.setColor(Color.blue);
    g.fillRect(80,200,220,90);
    g.fillRect(100,10,90,80);

    g.setColor(Color.lightGray);
    g.fillRect(locx,locy,width,height);

    g.setColor(Color.red);
    g.fillRect(200,0,45,45);
    g.fillRect(0,100,70,200);

    g.setColor(Color.magenta);
    g.fillRect(200,55,60,135);
}

//update the center rectangle
void updateRectangle() {

    switch (state) {
    case DOWN:
        locy += 2;
        if (locy >= 110) {
        state = UP;
        }
        break;
    case UP:
        locy -= 2;
        if (locy <= 90) {
        state = RIGHT;
        }
        break;
    case RIGHT:
        locx += 2;
        if (locx >= 90) {
        state = LEFT;
        }
        break;
    case LEFT:
        locx -= 2;
        if (locx <= 70) {
        state = DOWN;
        }
        break;
    }
}

public void run() {

    while (true) {
        repaint();  
        updateRectangle();              
        try {
        Thread.sleep (REFRESH_RATE);    
        } catch (Exception exc) { };
    }
}

public void stop() {

    if (animation != null) {
    animation.stop();
    animation = null;
    }
}
}

Solution

    1. import java.awt.*;
      Change that to
      import javax.swing.*;
    2. public class Broadway extends Applet ..
      Change that to
      public class Broadway extends JApplet ..
    3. Move all the custom painting into a JPanel. Override paintComponent(Graphics) rather than paint(Graphics). A JPanel is double buffered by default.
    4. Do animation using a Swing Timer.

    As a general tip

    Code a frame & launch it from a link using Java Web Start before considering using an applet.

    Update

    This code implements most of the advice above, and displays the resulting smooth, buffered animation in an option pane. It could instead be displayed in a JFrame or JApplet.

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.*;
    
    public class Broadway extends JPanel {
    
        int locx, locy; // location of rectangle
        int width, height; // dimensions of rectangle
        Timer timer;
    // direction of motion
        static final byte UP = 0;
        static final byte DOWN = 1;
        static final byte LEFT = 2;
        static final byte RIGHT = 3;
        byte state; // state the rect is in
    // length of pausing interval in ms
        static final int REFRESH_RATE = 100;
    
        public Broadway() {
    
            setBackground(Color.black);
    
            locx = 80; // parameters of center rect
            locy = 100;
            width = 110;
            height = 90;
            state = UP;
    
            ActionListener listener = new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    repaint();
                    updateRectangle();
                }
            };
    
            timer = new Timer(this.REFRESH_RATE, listener);
        }
    
        public void start() {
            timer.start();
        }
    
        public void stop() {
            timer.stop();
        }
    
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.yellow);
            g.fillRect(0, 0, 90, 90);
            g.fillRect(250, 0, 40, 190);
            g.fillRect(80, 110, 100, 20);
    
            g.setColor(Color.blue);
            g.fillRect(80, 200, 220, 90);
            g.fillRect(100, 10, 90, 80);
    
            g.setColor(Color.lightGray);
            g.fillRect(locx, locy, width, height);
    
            g.setColor(Color.red);
            g.fillRect(200, 0, 45, 45);
            g.fillRect(0, 100, 70, 200);
    
            g.setColor(Color.magenta);
            g.fillRect(200, 55, 60, 135);
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    
    //update the center rectangle
        void updateRectangle() {
    
            switch (state) {
                case DOWN:
                    locy += 2;
                    if (locy >= 110) {
                        state = UP;
                    }
                    break;
                case UP:
                    locy -= 2;
                    if (locy <= 90) {
                        state = RIGHT;
                    }
                    break;
                case RIGHT:
                    locx += 2;
                    if (locx >= 90) {
                        state = LEFT;
                    }
                    break;
                case LEFT:
                    locx -= 2;
                    if (locx <= 70) {
                        state = DOWN;
                    }
                    break;
            }
        }
    
        public static void main(String[] args) {
            Runnable r = new Runnable() {
    
                @Override
                public void run() {
                    Broadway bw  = new Broadway();
    
                    bw.start();
                    JOptionPane.showMessageDialog(null, bw);
                    bw.stop();
                }
            };
            // Swing GUIs should be created and updated on the EDT
            // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
            SwingUtilities.invokeLater(r);
        }
    }