特定 Java Swing 算法中 ActionListener 的延迟?

Delay in ActionListener in specific Java Swing algorithm?

我以前在这里问过这个问题,但由于太不具体而且没有 "minimal reproducible example" 的特点而被删除了。 :)

基本上,只要用户点击 "Start":

,我希望我的算法按如下方式运行

这是我尝试实施 "Timer" 延迟的代码,但严重失败:

    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();
    }
}

我尝试过很多不同的方法,但我似乎不明白如何正确使用 "Timer"。 如果有人花时间尝试在下面的代码中实现它,我将不胜感激,因为到目前为止,简单地向我解释它并没有带我到任何地方。 :(

非常感谢!

这里有一个明显的问题:

@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();  // **** here ****
        button[array[x]].setBackground(Color.black);
    }
}

您在调用 timer.start() 之后立即调用 timer.stop() 并且没有给计时器机会。也许您想在 Timer 完成其业务后从它自己的 ActionListener 中停止它。

此外,这不编译:

timer = new Timer(delay, action);

在发布的代码中没有任何名为 action 的变量,但在此方法调用中除外,这应该会导致“找不到符号”错误。

所以解决方案可能是:

timer.addActionListener(timerDelay, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        if (someCondition) {
            // do Timer's business repeating until condition is false
        } else {
            // condition now false
            ((Timer) e.getSource()).stop(); // stop the Timer
        }       
    }
});

请注意,在 if 块中,您可以递增一个计数器变量,其中一个在启动计时器之前设置为 0,然后在 someCondition 中检查该变量的状态。如果需要,您可以通过这种方式重复一个动作 5 次。

我误读了你在上一个问题中的一个要求:Specific Delay in Java Swing within an ActionListener?,所以我会在这里再次重申我的建议space:

在你的class中:

  1. 创建一个 ArrayList 作为实例变量,这样您就可以在 ActionListeners 中访问 ArrayList

在添加到按钮的 ActionListener 中,您需要:

  1. 将要切换颜色的 6 个随机按钮添加到 ArrayList。所以你将创建一个循环来随机选择 6 个按钮。
  2. 设置 ArrayList 中第一个按钮的颜色
  3. 启动计时器

然后在定时器的 ActionListener 中:

  1. 重置 ArrayList 中第一个按钮的颜色
  2. 从 ArrayList 中删除第一个按钮
  3. 如果 ArrayList 为空,则停止 Timer
  4. 否则获取第一个按钮并将颜色更改为红色

因此,当您单击“开始”按钮时,第一个按钮显示为红色。它将保持红色,直到定时器在 500 毫秒后触发,此时它将重置为默认值并更改另一个按钮。定时器将在 500 毫秒后再次触发,并且该过程不断重复。

请注意定时器的 ActionListener 中没有循环代码。定时器将每 500 毫秒持续生成一个事件,直到您停止定时器。

如果您需要更多帮助,请提出后续问题,不要创建新话题。