Search code examples
javaswingbackgroundawtscreensaver

how do i make a JPanel background that won't update?


I'm trying to make an animated screensaver with some changing colors and moving shapes and I also want it to have a sort of trail effect (like how the most recent color on each pixel is continually drawn there if you don't set your background color). I achieved this effect once before, but I don't know how I did it. Currently the result is a moving square with that changes colors across a grey background. ScreenSaver.java

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JPanel;
import javax.swing.Timer;

public class ScreenSaver extends JPanel
{
    public static Component sc;
    public int delay = 1000/2;
    public int state = 0;
    public int re = 255;
    public int gr = 0;
    public int bl = 0;
    public int d = 1;
    ScreenSaver()
    {
        ActionListener counter = new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                updateUI();
                repaint();
            }
        };
        new Timer(delay, counter).start();
        System.out.println("this is the secret screensaver that appears after 30 seconds of no mouse activity");//i have this line here so it doesn't print every time the screen updates
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        this.setBackground(null);
        if (state == 0)
        {
            gr++;
            if(gr == 255)
                state = 1;
        }
        if (state == 1)
        {
            re--;
            if(re == 0)
                state = 2;
        }
        if (state == 2)
        {
            bl++;
            if(bl == 255)
                state = 3;
        }
        if (state == 3)
        {
            gr--;
            if(gr == 0)
                state = 4;
        }
        if (state == 4)
        {
            re++;
            if(re == 255)
                state = 5;
        }
        if (state == 5)
        {
            bl--;
            if(bl == 0)
                state = 0;
        }
        g.setColor(new Color(re, gr, bl));
        d++;
        g.fillRect(d, 50, 50, 50);
    }
    public static void main(String[] args)
    {
        //ScreenSaver sc = new ScreenSaver();
    }
}

Main.java: (ScreenSaver.java is called as an object through this file)

import java.awt.Color;
import java.awt.Graphics;
//import java.util.Random;

//import javax.swing.AbstractAction;
//import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.Timer;

public class FinalProject extends JPanel implements MouseMotionListener
{
    public int delay = 1000/2;
    public boolean screenActive = true;
    public int why = 1;
    FinalProject()
    {
        ActionListener counter = new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                updateUI();
                repaint();
            }
        };
        new Timer(delay, counter).start();
    }
    static JFrame jf = new JFrame();

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        this.setBackground(Color.BLACK);
        if (screenActive)
        {
            why++;
        }
        if (why == 6)
        {
            why = 0;
            System.out.println("inactivity detected");
            screenActive = false;
            ScreenSaver sc = new ScreenSaver();
            jf.add(sc);
        }
    }

    public static void main(String[] args) throws InterruptedException
    {
        System.out.println("Welcome to Computer Simulator 0.1");
        System.out.println("this is the main screen");
        FinalProject e = new FinalProject();
        //ScreenSaver sc = new ScreenSaver();
        jf.setTitle("game");
        jf.setSize(500,500);
        //jf.setUndecorated(true);
        //jf.setBackground(new Color(1.0f,1.0f,1.0f,0.5f));
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //jf.add(new ScreenSaver());
        jf.add(e);
    }

    @Override
    public void mouseDragged(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseMoved(MouseEvent MOUSE_MOVED)
    {

    }
}

Solution

  • Don't invoke updateUI(). All you need is the repaint() to cause the component to repaint itself.

    One way it to do the drawing to a BufferedImage and then use the BufferedImage to create an ImageIcon which you add to a JLabel.

    The other way is to keep a list of object that you want to paint and then just iterate through the list each time the component is repainted.

    Check out Custom Painting Approches for working examples and an analysis of when you might use either approach.