2016-11-09 95 views
0

我正试图做一个简单的程序,其中一个球通过JFrame中的Canvas移动。 我想让主线程更新屏幕中球的位置并在画布上打印每一帧,而另一个线程更新缓冲区上的每个下一帧。这是我的代码:如何使用多个线程创建缓冲平滑动画?

public class SynchAnimation { 

private JFrame frame; 
private Canvas canvas; 
private BufferedImage frameImage; 
private Graphics bfg; 
private final int width = 500, height = 500; 
private int x, y; 
private DrawingThread drawingThread; 
private final Object key; 

public SynchAnimation() { 

    key = new Object(); 

    x = 200; 
    y = 200; 

    frame = new JFrame("Synchronized animation"); 
    frame.setSize(width, height); 
    frame.setLocationRelativeTo(null); 

    frameImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
    bfg = frameImage.createGraphics(); 

    canvas = new Canvas() { 
     @Override 
     public void paint(Graphics g) { 
      g.drawImage(frameImage, 0, 0, null); 
     } 
    }; 
    canvas.setSize(width, height); 

    frame.add(canvas); 
    frame.pack(); 
    frame.setVisible(true); 
} 

public void mainRun() { 

    drawingThread = new DrawingThread(); 
    drawingThread.start(); 

    while (true) { 
     synchronized (key) { 
      x += 1; 
      y += 1; 
      canvas.repaint(); 
     } 
    } 
} 

class DrawingThread extends Thread { 

    @Override 
    public void run() { 
     while (true) { 
      synchronized (key) { 
       bfg.clearRect(0, 0, width, height); 
       bfg.setColor(Color.BLUE); 
       bfg.fillRect(0, 0, width, height); 
       bfg.setColor(Color.ORANGE); 
       bfg.fillOval(x, y, 40, 40); 
      } 
     } 
    } 
} 

public static void main(String[] args) { 
    new SynchAnimation().mainRun(); 
} 

为什么它仍然闪烁着地狱?我认为同步块会做伎俩。这实际上不是一个GUI问题,而是一个线程问题......我这样做是为了理解尝试访问和修改相同数据时同步线程是如何工作的。 感谢您的帮助!

+1

我很震惊,这种即使sorta工程。你不会开始画一个线程 - 你重写组件的'paint()'和/或'update()'方法。 GUI工具包是基于事件的,并且这些应用程序有一个结构。有关Swing组件/事件流程/绘图的概述,请参阅https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html。 – BadZen

+1

此外,您应该知道,语言规范对线程获取监视器锁定的顺序绝对没有任何要求(从“synchronized”开始 - 对于其中一个循环而言,完全有效的行为永远不会运行,方式你已经编码了,从我链接的线索和C&P的示例项目开始,然后从那里修改,示例代码是完全错误的。=/ – BadZen

+0

作为附加注释同步使用什么:为了防止同时访问在这个区块中,并行访问是不可能的,因此会从单独的线程中获得任何好处,只能在关键部分使用它们(例如:访问资源) – Gildraths

回答

0

你可能想重载paintComponent()而不是