大家好,我正在做一个线程来更新JFrame上的球,所以我重新绘制了屏幕。。。然后绘制球更新其位置。。然后再次绘制屏幕。。。把球和同样的循环。。。这是代码
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
Thread t = new Thread()
{
public void run()
{
while(true)
{
repaint();
b2.update(ob,2);
b2.paint(ob.getGraphics());
b2.setT(b2.getT() + 1);
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
System.out.println("Error in Sleeping");
}
}
}
};
t.start();
}
但问题是我看不到球。。。屏幕上的油漆总是覆盖球,球就像在Jframe下面一样。。
如果您想在Swing中使用动画,建议使用javax.swing.Timer
类。此类允许您定期对事件调度线程执行操作。
- Swing
Timer
教程 - SO上发布的动画示例(链接到SO btw上的Swing wiki中)
一些一般规则
- Swing不是线程安全的,您应该只在事件调度线程的上下文中更新UI组件
- 您不控制绘制过程,重新绘制管理器控制。您可以通过调用
repaint
来请求进行更新,但在尝试更新显示时,不应直接调用update
和paint
- 绘制子系统使用的
Graphics
上下文是一个共享资源,不能保证在绘制周期之间是相同的,您永远不应该维护对它的引用。您也不应该依赖JComponent#getGraphics
的结果。此方法能够返回null
示例解决方案
你有很多选择,这取决于你最终想要实现的目标。
你可以使用SwingWorker
,但考虑到你要进入的是一个无限循环,而且使用SwingUtilities#invokeLater
比实际使用publish
方法更容易,这种方法实际上会做更多的工作。
您也可以使用Thread
,但最终会遇到与使用SwingWorker
相同的问题
Simplipset解决方案实际上是一个javax.swing.Timer
public class Blinky {
public static void main(String[] args) {
new Blinky();
}
public Blinky() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new BlinkyPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class BlinkyPane extends JPanel {
private JLabel blinkyLabel;
private boolean blink = false;
public BlinkyPane() {
setLayout(new GridBagLayout());
blinkyLabel = new JLabel("I'm blinking here");
blinkyLabel.setBackground(Color.RED);
add(blinkyLabel);
Timer timer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
blink = !blink;
if (blink) {
blinkyLabel.setForeground(Color.YELLOW);
} else {
blinkyLabel.setForeground(Color.BLACK);
}
blinkyLabel.setOpaque(blink);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
}
}
您可以查看Swing中的Swing Timer和Concurrency以了解更多信息
如果您访问EDT(事件调度线程)之外的GUI组件,则可能会遇到奇怪的问题。相反,如果您在EDT中执行长时间运行的任务,则也会遇到问题。
查看这篇文章了解更多关于GUI Threading in Java
的信息