我正在尝试让我的 JButton 为我正在创建的游戏闪烁红色。该网站上的所有解决方案都建议使用线程并将其置于 sleep 状态或使用计时器,但是,暂停似乎是在颜色变化之后出现的
这是我的代码:
Color cb = board[Y1][X1].getBackground();
board[Y1][X1].setBackground(Color.RED);
//Pause
board[Y1][X1].setBackground(cb);
如果我在第 3 行放置一个线程并将其置于 hibernate 状态并注释掉第 4 行,那么在 JButton 变红之前会出现暂停。 (记事板只是 JButton 的二维数组)
最佳答案
发生这种情况的原因有很多,同样,修复它的方法也有很多。
根据您的描述,听起来您正在尝试从事件调度线程外部更新 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();
}
}
}
看看Concurrency in Swing和 How to Use Swing Timers了解更多详情。
更复杂的解决方案将允许您使用 Thread
,但需要使用 SwingUtilities.invokeLater
更新 UI,这会将事件放置到 EDT这将执行 Runnable
接口(interface),您将使用它来更新 UI。这可能会出现同步问题,因为您调用的 Thread
会在触发实际事件之前继续运行,并可能导致一些脏更新,除非您仔细控制更新过程...
关于Java Swing JButton 时间延迟(闪烁),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43666476/