2015-11-25 78 views
0

因此,对于一个个人项目,我一直试图用Java创建一个程序,以使基本动画出现在Swing应用程序中。据我所知,我所做的一切都是正确的,并且据我所知它正在工作,但是当我运行该应用程序时,它不会让我在没有任务管理器的情况下关闭应用程序,并且当我强制退出应用程序IntelliJ时我“过程完成退出代码1”。它也不会在屏幕上显示我的动画,尽管显示正常的图形事物如线条。Swing animation does not working

这里是我的JFrame代码:

package animtest; 

import javax.swing.*; 

public class AnimTest extends JFrame { 

    public void addComponents() { 
     AnimPanel panel = new AnimPanel(); 
     setContentPane(panel); 
    } 

    public AnimTest(String string) { 
     super(string); 
    } 

    public static void main(String[] args) { 
     AnimTest frame = new AnimTest("Animation Test"); 

     frame.addComponents(); 
     frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 

} 

这里是我的JPanel代码:

package animtest; 

import javax.imageio.ImageIO; 
import javax.swing.*; 
import java.awt.*; 
import java.io.File; 
import java.io.IOException; 
import java.util.concurrent.TimeUnit; 

public class AnimPanel extends JPanel { 

    Image[] marsExploding = new Image[3]; 

    public AnimPanel() { 
     try { 
      marsExploding[0] = ImageIO.read(new File("res/MarsExploding.png")); 
      marsExploding[1] = ImageIO.read(new File("res/MarsExploding2.png")); 
      marsExploding[2] = ImageIO.read(new File("res/MarsExploding3.png")); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 

    @Override 
    public void paintComponent(Graphics g2) { 
     Graphics2D g = (Graphics2D) g2.create(); 
     g.setColor(Color.white); 

     for (int i = 0; i < marsExploding.length; i++) { 
      g.drawImage(marsExploding[i], (getWidth()/2) - 128, (getHeight()/2) - 128, 256, 256, null); 

      try { 
       TimeUnit.SECONDS.sleep(500); 
      } catch (InterruptedException ex) { 
       Thread.currentThread().interrupt(); 
      } 

      g.fillRect(0, 0, getWidth(), getHeight()); 
     } 

     g.dispose(); 
     repaint(); 
    } 

} 

任何帮助是极大的赞赏,谢谢!

编辑1

OK,所以这是我的新面板的代码,它应履行Swing的合同,并发:

package animtest; 

import javax.imageio.ImageIO; 
import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.File; 
import java.io.IOException; 
public class AnimPanel extends JPanel { 

    Image[] marsExploding = new Image[3]; 

    Graphics2D g; 

    int currentFrame = 0; 

    public AnimPanel() { 
     try { 
      marsExploding[0] = ImageIO.read(new File("res/MarsExploding.png")); 
      marsExploding[1] = ImageIO.read(new File("res/MarsExploding2.png")); 
      marsExploding[2] = ImageIO.read(new File("res/MarsExploding3.png")); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 

     Timer timer = new Timer(500, null); 
     timer.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       displayNewFrame(currentFrame); 

       if (currentFrame < 2) { 
        currentFrame++; 
       } else { 
        currentFrame = 0; 
       } 
      } 
     }); 
     timer.start(); 
    } 

    @Override 
    public void paintComponent(Graphics g2) { 
     super.paintComponent(g2); 

     g = (Graphics2D) g2.create(); 
    } 

    public void displayNewFrame(int frame) { 
     g.fillRect(0, 0, getWidth(), getHeight()); 

     g.drawImage(marsExploding[frame], (getWidth()/2) - 128, (getHeight()/2) - 128, 256, 256, null); 
    } 

} 

然而,这实际上并没有显示任何内容到屏幕上。

+2

* “据我所知,我所做的一切权利” * - 'TimeUnit.SECONDS.sleep(500);'是不正确的。查看[Swing中的并发](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/),了解为什么和[如何使用Swing定时器](http://docs.oracle.com/javase/tutorial /uiswing/misc/timer.html)来解决这个问题 – MadProgrammer

+0

你已经通过调用paintComponent的super方法来断开paint链的合约。另外,请不要在任何'paint'方法内调用'repaint',这会导致你无法结束问题并且抢走你控制动画的时间的能力。 – MadProgrammer

+0

好的,谢谢。我应该简单地使用Thread.sleep(500);而不是? – TheAustralianBirdEatingLouse

回答

2

Swing是一个单线程框架,这意味着任何长时间运行或阻塞的事件调度线程的上下文中的调用都将阻止UI被更新或允许用户与之交互,从而使得你的用户界面就好像挂起了一样(因为它基本上已经)。

查看Concurrency in Swing了解更多详情。

而不是试图在paint方法中使用TimeUnit.SECONDS.sleep(500);,你应该有一些后台线程,它定期打勾,并允许你相应地更新UI。问题是,Swing也不是线程安全的,这意味着你不应该尝试从Event Dispatching Thread的上下文之外创建或更新UI。

但对于基本的解决方案,您可以使用Swing Timer,这将在EDT的上下文中定期触发ActionListener,使其可以安全地用于UI。

有关更多详细信息,请参见How to use Swing Timers

Swing中的绘画是通过一系列链接的方法调用执行的,自定义绘画需要您在这些链接中插入代码,paintComponent是最受欢迎的。

但是,您需要通过调用super涂装方法来履行这些链接的合同。

Painting in AWT and SwingPerforming Custom Painting更多细节