0

I am trying to understand if it is possible to change the color of existing graphics while my application runs, (something of a flicker between multiple different colors).

I have a start shape that is drawn out using the GeneralPath class and I also have my a random RGB color code selector working properly. Is it possible to change the color maybe with using repaint(); to have the color of my star change between the 3 selected colors which were randomly selected from my createRandomColor() method?

Code

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import static java.lang.Math.random;
import java.util.Vector;
import javax.swing.JApplet;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Sandbox extends JApplet {
    DrawingStar canvas;

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Sandbox path = new Sandbox();
        path.init();
        frame.getContentPane().add(path);
        frame.setSize(250, 250);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void init() {
        Container container = getContentPane();
        canvas = new DrawingStar();
        container.add(canvas);
    }

}

class DrawingStar extends Canvas {
    Vector generalPaths;
    private List<Color> colors;

    public DrawingStar() {
        colors = new ArrayList<Color>();

        for (int i = 0; i < 3; i++) {
            colors.add(createRandomColor());
        }

        setBackground(Color.white);
        setSize(400, 400);
        generalPaths = new Vector();

        GeneralPath gp1;

        gp1 = new GeneralPath();
        gp1.moveTo(50, 120);
        gp1.lineTo(70, 180);
        gp1.lineTo(20, 140);
        gp1.lineTo(80, 140);
        gp1.lineTo(30, 180);
        gp1.closePath();
        generalPaths.addElement(gp1);
    }

    public void paint(Graphics g) {
        Graphics2D g2D = (Graphics2D) g;
        g2D.translate(70.0f, -85.0f);
        g2D.draw((GeneralPath) generalPaths.elementAt(0));

        for (int i = 0; i < 3; i++) {
            Color color = colors.get(i);
            g2D.setColor(color);
            g2D.fill((GeneralPath) generalPaths.elementAt(0));
        }

        System.out.println("Is this working");
        repaint();
    }


    private Color createRandomColor(){
        int r = (int) (Math.random() * 256);
        int g = (int) (Math.random() * 256);
        int b = (int) (Math.random() * 256);
        Color color = new Color(r,g,b);

        return color;
    }

}

Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
jdave
  • 845
  • 2
  • 11
  • 27
  • The short answer is "yes", the long answer is "yes, but not the way you're doing it". First, applets are dead. They are deprecated and no longer support, you should move on. I would avoid using `Canvas` as a starting point, it's probably way to low a API for your needs. If you want to "animated" the change, then you probably should start with a Swing `Timer` and `JPanel` instead – MadProgrammer Nov 03 '18 at 21:55
  • @MadProgrammer do you happen to know of an example of this or where I could find one? – jdave Nov 03 '18 at 21:58
  • [Creating a GUI With JFC/Swing](https://docs.oracle.com/javase/tutorial/uiswing/), [Performing Custom Painting](https://docs.oracle.com/javase/tutorial/uiswing/painting/index.html), [Painting in AWT and Swing](https://www.oracle.com/technetwork/java/painting-140037.html), [How to Use Swing Timers](https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) – MadProgrammer Nov 03 '18 at 22:03
  • [And just about any previous question about animating color and/or timer and color](https://stackoverflow.com/search?q=%5Bjava%5D+%5Bswing%5D+timer+color) – MadProgrammer Nov 03 '18 at 22:04

1 Answers1

1

Applets are dead, long live HTML5

Time to move on...also, applet lifecycles are a lot more complicated then you've implemented.

An "alternative"

Canvas is a low level component which is probably not well suited to your needs. It's also not double buffered, so you're going to get flickering when it's repainted.

Don't call repaint from within any paint method, you won't like the results. Instead, schedule an update to occur at some point in the future.

This example simply makes use of a Swing Timer to act as a pseudo loop, which increments a counter and gets the next color and call's repaint, every second.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Sandbox {

    DrawingStar canvas;

    public static void main(String[] args) {
        new Sandbox();
    }

    public Sandbox() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                canvas = new DrawingStar();
                frame.getContentPane().add(canvas);
                frame.setSize(250, 250);
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    }

    class DrawingStar extends JPanel {

        Vector generalPaths;
        private List<Color> colors;
        private int colorIndex = 0;
        private Color color;

        public DrawingStar() {

            colors = new ArrayList<Color>();

            for (int i = 0; i < 3; i++) {
                colors.add(createRandomColor());
            }

            color = colors.get(0);

            setBackground(Color.white);
            generalPaths = new Vector();

            GeneralPath gp1;

            gp1 = new GeneralPath();
            gp1.moveTo(50, 120);
            gp1.lineTo(70, 180);
            gp1.lineTo(20, 140);
            gp1.lineTo(80, 140);
            gp1.lineTo(30, 180);
            gp1.closePath();
            generalPaths.addElement(gp1);

            Timer timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    colorIndex++;
                    if (colorIndex >= colors.size()) {
                        colorIndex = 0;
                    }

                    color = colors.get(colorIndex);
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
            Graphics2D g2D = (Graphics2D) g;
            g2D.translate(70.0f, -85.0f);
            g2D.draw((GeneralPath) generalPaths.elementAt(0));

            g2D.setColor(color);
            g2D.fill((GeneralPath) generalPaths.elementAt(0));
        }

        private Color createRandomColor() {
            int r = (int) (Math.random() * 256);
            int g = (int) (Math.random() * 256);
            int b = (int) (Math.random() * 256);
            Color color = new Color(r, g, b);

            return color;
        }

    }
}

Swing is NOT thread safe and is single threaded, hence the reason for using a Swing Timer

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366