You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swing/AWT事件队列中添加指定时长暂停?最佳实践

Swing/AWT事件间添加指定延迟的最佳实践

我开发了一款游戏,需要让某个组件闪烁红色后,经过短暂延迟恢复至正常颜色。用Thread.sleep(123)会直接阻塞事件调度线程(EDT),导致整个UI完全失去响应,显然不是可行方案。虽然可以在独立线程中执行暂停后调用SwingUtilities::invokeLater更新UI,但这类场景下有更标准的最佳实践。

问题示例代码

用户提供的示例代码中,在EDT内调用Thread.sleep(10_000)会导致窗口10秒内无法交互:

import javax.swing.*;
import java.awt.*;

public class cry {

    public static void main(final String[] args) {

        SwingUtilities.invokeLater(cry::blah);

    }

    private static void blah() {
        final JFrame frame = new JFrame();
        frame.setTitle("ABC");
        frame.setLocationByPlatform(true);
        frame.setSize(300, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        try {
            Thread.sleep(10_000); //sleep for 10 seconds
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        
        frame.setTitle("XYZ");
    }

}

最优解决方案:使用javax.swing.Timer

Swing提供的Timer是专门为EDT环境设计的延迟任务工具,所有回调逻辑都会自动在EDT上执行,既不会阻塞UI,又能保证UI操作的线程安全性,是这类场景的标准选择。

改造示例代码(替换sleep实现标题延迟更新)

将原代码中的Thread.sleep替换为Timer,实现10秒后更新标题且不阻塞UI:

import javax.swing.*;
import java.awt.*;

public class cry {

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(cry::blah);
    }

    private static void blah() {
        final JFrame frame = new JFrame();
        frame.setTitle("ABC");
        frame.setLocationByPlatform(true);
        frame.setSize(300, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        // 创建一次性Timer,延迟10秒触发
        Timer titleUpdateTimer = new Timer(10000, e -> {
            frame.setTitle("XYZ");
            // 执行完毕后停止Timer(因为设置了只执行一次,这步也可以省略)
            ((Timer) e.getSource()).stop();
        });
        titleUpdateTimer.setRepeats(false); // 设置为仅执行一次
        titleUpdateTimer.start(); // 启动Timer
    }

}

组件闪烁场景的实现

针对游戏中组件闪烁红色后恢复的需求,用Timer可以轻松实现:

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

public class ComponentBlinkExample {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ComponentBlinkExample::createUI);
    }

    private static void createUI() {
        JFrame frame = new JFrame("组件闪烁示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);
        frame.setLayout(new FlowLayout());

        JButton blinkButton = new JButton("点击闪烁");
        frame.add(blinkButton);

        // 保存按钮原始背景色
        Color originalColor = blinkButton.getBackground();

        blinkButton.addActionListener((ActionEvent e) -> {
            // 第一步:将按钮设为红色
            blinkButton.setBackground(Color.RED);

            // 创建延迟恢复颜色的Timer,500毫秒后触发
            Timer blinkTimer = new Timer(500, event -> {
                blinkButton.setBackground(originalColor);
                ((Timer) event.getSource()).stop();
            });
            blinkTimer.setRepeats(false);
            blinkTimer.start();
        });

        frame.setVisible(true);
    }
}

为什么Timer是最优选择?

  • 线程安全:Timer的回调自动在EDT执行,无需手动调用invokeLater,避免了线程安全问题。
  • 不阻塞UI:Timer不会占用EDT的执行时间,UI在延迟期间仍能正常响应交互。
  • 简洁可控:支持重复执行、随时启停,比手动管理线程+延迟的实现更简洁可靠。

内容的提问来源于stack exchange,提问作者davidalayachew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 10:44:55