GRoutar
GRoutar

Reputation: 1425

Screen flashing white during animation

I am developing a Java program and I started off with a simple animation. It consists on displaying a set of frames stored in an array (40 frames).

The animation itself is working corretly, although whenever I run it I get this random flickering (Screen flashes white). I don't know what it might be related to, but I'm guessing it has to do with lack of optimization. Any solutions? Here's the code below

//Handles the main interface
MainUI.java

package gui;

import java.awt.BorderLayout;

public class MainUI extends JFrame implements ActionListener{

    //main panel
    private JPanel contentPane;

    //animation
    private ImageIcon[] frames; //animation frames
    private Timer timer; 
    private int delay = 50; //0,5s
    private int currentFrame = 0;

    public MainUI() {

        Map M = new Map();

        loadAnimation(M);

        //Main frame
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 640, 360);
        setResizable(false);
        setTitle("Monopoly Java");

        //Panel
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        JLabel label = new JLabel("");
        //label.setIcon(frames[0]);
        contentPane.add(label, BorderLayout.CENTER);
    }

    public void loadAnimation(Map M) {

        timer = new Timer(delay, this);
        timer.start();

        frames = M.getFrames();
    }

    public void paint(Graphics g) {

        super.paintComponents(g);

        frames[currentFrame].paintIcon(this, g, 0, 0);

        if (currentFrame == frames.length - 1) timer.stop();
        else currentFrame++;
    }

    public void actionPerformed(ActionEvent e) {
        repaint();
    }
}

/----

//Class responsible for loading the images
Map.java

package gui;

import javax.swing.ImageIcon;

public class Map {

    //animation frames array
    private ImageIcon[] frames;

    public Map() {  

        loadAnimationFrames();
    }

    public void loadAnimationFrames() {

        //Loading animation frames
        frames = new ImageIcon[40];

        for (int i = 0; i < 40; i++) {

            String frameName = "f" + (i + 1);
            frames[i] = new ImageIcon("src/gui/Images/Frames/" + frameName + ".jpg");
        }
    }

    public ImageIcon[] getFrames() {
        return frames;
    }
}

/----

//class which contains main
main.java

package gui;

import java.awt.EventQueue;

public class main {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MainUI frame = new MainUI();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

Upvotes: 1

Views: 694

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285430

You've got some problems:

  • Don't draw directly in the JFrame, ever. JFrames have a huge amount of functionality that can be compromised if you override their paint methods. Also since they don't have a paintComponent method, you don't get default double buffering -- a key loss.
  • Instead draw in a JPanel or JComponent extending class.
  • And draw in the paintComponent(Graphics g) method not the paint method. This gains you default double buffering which will make your animations seem smoother.
  • Call the appropriate super method. You're calling super.paintComponents(....) for some reason. For paintComponent, that would be super.paintComponent(g) (no s)
  • Get your program logic out of all painting method. The logic should be in the timer, and only painting should be done in your painting method.

  • Myself, I wouldn't do anything that you're doing, but instead would simply swap ImageIcons in a JLabel inside of my Timer and that's it. Easy and clean.

For example:

public void actionPerformed(ActionEvent e) {
    myJLabel.setIcon(frames[currentFrame]);
    currentFame++;
    if (currentFrame >= frames.length) {
        timer.stop();
    }
}

Upvotes: 6

Related Questions