在JFrame Java中闪烁

大家好我正在做一个线程来更新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上发布的动画示例 (在Swt wiki中链接在SO btw上)

一些一般规则

  • Swing不是线程安全的,您应该只在Event Dispatching Thread的上下文中更新UI组件。
  • 您不会控制绘制过程,重绘管理器会这样做。 您可以通过调用repaint来请求更新,但在尝试更新显示时,不应直接调用updatepaint
  • paint子系统使用的Graphics上下文是一个共享资源,并且不保证在绘制周期之间是相同的,您永远不应该保持对它的引用。 您也不应该依赖于JComponent#getGraphics的结果,此方法能够返回null。

示例解决方案

您有很多选择,具体取决于您最终要实现的目标。

您可以使用SwingWorker ,但考虑到您要进入无限循环的事实并且使用SwingUtilities#invokeLater更容易然后实际使用publish方法,这种方法实际上会更多。

您也可以使用Thread ,但最终会遇到与使用SwingWorker相同的问题

对于您所呈现的内容,simpliset解决方案实际上是一个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 Timer和Swing中的并发以获取更多信息

如果您访问EDT(事件调度线程)之外的GUI组件,那么您可能会遇到奇怪的问题,如果您在EDT中执行长时间运行的任务,那么您也会遇到问题。

查看这篇文章,了解有关GUI Threading in Java更多信息