Search code examples
javaswingtimerjframeactionlistener

Delay in ActionListener in specific Java Swing algorithm?


I've asked this question here before, but it got taken down because it was too unspecific and didn't feature "minimal reproducible example". :)

Basically I want my algorithm to go as follows, as soon as a User clicks "Start":

  • On the 4x4 grid of buttons, a randomized button turns red, then black, with a delay of 500ms in between.
  • This is repeated 6 times

Here's the code where I've tried to implement "Timer" for the delay, but failed viciously:

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    public class TestMemoryGame extends JFrame {
    private JButton[] button = new JButton[16];
    private JButton start;
    private JPanel grid;
    private int counter = 6;
    private Timer timer;
    private int delay = 500;

    private Color babyBlue = new Color(137, 156, 240);
    private Color lightRed = new Color(255,69,0);

    public TestMemoryGame() {
        super();
        init();
    }

    public void init() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new GridBagLayout());
        setSize(500, 500);
        setBackground(Color.WHITE);

        grid = new JPanel(new GridLayout(4, 4));

        for (int x = 0; x < 16; x++) {
            button[x] = new JButton();
            button[x].setBackground(babyBlue);
            grid.add(button[x]);
        }
        grid.setPreferredSize(new Dimension(400, 400));
        add(grid);


        start = new JButton("START");
        start.setBackground(Color.ORANGE);
        start.setPreferredSize(new Dimension(150, 30));
        GridBagConstraints c = new GridBagConstraints();
        c.gridy = 1;
        c.insets.top = 10;
        add(start, c);

        start.addActionListener(startTimer);

        timer = new Timer(delay, action);

        pack();
        setVisible(true);
    }

    ActionListener startTimer = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            timer.start();
        }
    };

    ActionListener action = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            int[] array = new int[counter];
            for (int x = 0; x < counter; x++) {
                array[x] = (int)(Math.random() * 16);
                button[array[x]].setBackground(lightRed);
                timer.start();
                //Delay of 500
                timer.stop();
                button[array[x]].setBackground(Color.black);
            }
        }
    };

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

I've tried this with so many different approaches, but I just don't seem to get how to use "Timer" correctly. I would really appreciate, if someone took the time to try and implement it in the code below, since simply explaining it to me hasn't lead me anywhere so far. :(

Thanks a lot!


Solution

  • I misread one of your requirements in your last question: Specific Delay in Java Swing within an ActionListener?, so I will restate my suggestions here again where I have more space:

    In your class:

    1. Create an ArrayList as an instance variable so you can access the ArrayList in your ActionListeners

    In the ActionListener you add to your button you need to:

    1. add the 6 random buttons that you want to toggle the color to the ArrayList. So you will create a loop to randomly pick 6 buttons.
    2. set the Color of the first button in the ArrayList
    3. start the Timer

    In the ActionListener of the Timer you would then:

    1. reset the Color of the first button in the ArrayList
    2. remove the first button from the ArrayList
    3. if the ArrayList is empty, you stop the Timer
    4. else get the first button and change the Color to Red

    So, when you click the Start button, the first button is colored Red. It will remain Red until the Timer fires 500ms later at which time it is reset to the default and another button is changed. The Timer will fire again in 500ms and the process keeps repeating.

    Note how there is no looping code in the ActionListener of the Timer. The Timer will keep generating an event every 500ms until you stop the Timer.

    If you need more help, then ask a follow up question, don't create a new thread.