Java Swing JButton时间延迟(闪烁)

我正试图让我的JButton闪烁红色为我正在创建的这个游戏。 本网站上的所有解决方案都建议使用一个线程并将其置于睡眠状态或使用计时器,但是,颜色变化之后似乎会出现暂停消息

这是我的代码:

Color cb = board[Y1][X1].getBackground(); board[Y1][X1].setBackground(Color.RED); //Pause board[Y1][X1].setBackground(cb); 

如果我放一个线程并让它在第3行睡觉并注释掉第4行,那么暂停将在JButton变为红色之前出现。 (注意板只是JButtons的2D数组)

可能出现这种情况的原因有很多,同样,可以通过多种方式解决。

根据您的描述,听起来您正在尝试从事件调度线程之外更新UI。

Swing是一个单线程环境,它也不是线程安全的。 基本上这意味着,期望UI的所有交互/更改都在EDT的上下文中执行。 不遵守这条规则可能导致各种奇怪和奇妙的行为。

最简单的解决方案是使用javax.swing.Timer ,它允许您安排定期事件,这些事件保证在EDT中执行,例如

华而不实

 import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class FlashyButton { public static void main(String[] args) { new FlashyButton(); } public FlashyButton() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private JButton button; private Color[] colors = new Color[]{Color.RED, Color.YELLOW}; public TestPane() { button = new JButton("Flash Gorden"); button.setContentAreaFilled(false); button.setBorderPainted(false); button.setFocusPainted(false); button.setOpaque(true); button.setBackground(Color.YELLOW); setLayout(new GridBagLayout()); add(button); Timer timer = new Timer(500, new ActionListener() { private int counter = 0; @Override public void actionPerformed(ActionEvent e) { counter++; if (counter % 2 == 0) { button.setBackground(colors[0]); } else { button.setBackground(colors[1]); } } }); timer.start(); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.dispose(); } } } 

有关更多详细信息,请参阅Swing中的Concurrency和如何使用Swing Timers 。

更复杂的解决方案允许您使用Thread ,但需要使用SwingUtilities.invokeLater更新UI,这会将事件放置到将执行Runnable接口的EDT上,您将使用该接口来更新UI。 这可能有同步问题,因为您正在调用的Thread将在触发实际事件之前继续运行并且可能导致一些脏更新,除非您仔细控制更新过程…