使用按钮Java Swing启动动画

时间:2018-11-14 22:22:55

标签: java swing button jbutton

我想用一个开始按钮在屏幕上创建一些物体(“太空飞船”)的动画。这是我到目前为止的内容:

public class SpaceGame extends JPanel implements ActionListener {
    //The list of spaceships that should be painted
    LinkedList<Spaceship> playingList = new LinkedList<Spaceship>(); 
    Timer t = new Timer(5, this);

    @Override
    public void actionPerformed(ActionEvent e) {
        ListIterator<Spaceship> iter = playingList.listIterator();
        while (iter.hasNext()) {
            Spaceship s = iter.next();
            s.moveSpaceship();

        }
        repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        for (Spaceship s : playingList)
            s.drawSpaceship(g);
        t.start();
    }

    public static void main(String[] args) {
        SpaceGame game = new SpaceGame();
        JFrame fr = new JFrame();
        fr.setTitle("SPACE GAME");
        fr.setSize(990,690);
        fr.add(game);

        game.playingList .add(new Spaceship(3, 0, 570));
        game.playingList .add(new Spaceship(1, 250, 570));
        game.playingList .add(new Spaceship(2, 500, 570));


        JButton start = new JButton("START");
        start.addActionListener(game);
        fr.add(start,BorderLayout.SOUTH);

        fr.setVisible(true);
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

}

其中:

import java.awt.Graphics;

public class Spaceship {
    int initialSpeed;
    int locX, locY; //current location 

    public Spaceship(int initalSpeed, int initX, int initY) {
        this.initialSpeed = initalSpeed;
        locX = initX;
        locY = initY;
    }

    public void drawSpaceship(Graphics g) {
        g.setColor(Color.GREEN);
        g.fillOval(locX, locY, 100, 40);
    }

    public void moveSpaceship() {
        locY -= initialSpeed;
    }


}

很酷的想法是,按下按钮会触发动画。问题在于动画将在不按下开始按钮的情况下自动开始,然后在结束时该按钮无效。我该如何解决?

1 个答案:

答案 0 :(得分:1)

让我们从显而易见的开始...

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    for (Spaceship s : playingList)
        s.drawSpaceship(g);
    t.start();
}

t.start内部调用paintComponent是一个非常非常非常糟糕的主意。您无法控制绘制过程(即调用paintComponent的时间),因此可能出于多种原因在任何时候随时调用它。

您应该查看Painting in AWT and Swing,以了解有关绘画在Swing中如何工作的更多详细信息

绘画应仅绘制组件的当前状态,而无需其他任何内容。

第二个问题是Timer和按钮都在调用相同的actionPerformed方法,这实际上是没有意义的。实际上,在理想环境中,您不会像这样直接实现ActionListener,而是利用Anonymous Classes来防止外部类直接或间接调用该方法。

那么,解决方案是什么?在您的SpaceGame中添加一种方法,可以调用该方法以开始动画,例如...

public class SpaceGame extends JPanel implements ActionListener {
  //The list of spaceships that should be painted

  LinkedList<Spaceship> playingList = new LinkedList<Spaceship>();
  Timer t = new Timer(5, this);

  public void start() {
    if (t.isRunning()) {
      return;
    }
    t.start();
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    ListIterator<Spaceship> iter = playingList.listIterator();
    while (iter.hasNext()) {
      Spaceship s = iter.next();
      s.moveSpaceship();

    }
    repaint();
  }

  public void paintComponent(Graphics g) {
    super.paintComponent(g);

    for (Spaceship s : playingList) {
      s.drawSpaceship(g);
    }
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        SpaceGame game = new SpaceGame();
        JFrame fr = new JFrame();
        fr.setTitle("SPACE GAME");
        // This is unadvisable :/
        fr.setSize(990, 690);
        fr.add(game);

        game.playingList.add(new Spaceship(3, 0, 570));
        game.playingList.add(new Spaceship(1, 250, 570));
        game.playingList.add(new Spaceship(2, 500, 570));

        JButton start = new JButton("START");
        start.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(java.awt.event.ActionEvent e) {
            game.start();
          }
        });
        fr.add(start, BorderLayout.SOUTH);

        fr.setVisible(true);
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      }
    });
  }
}

然后更新您的主要方法以调用它...

public static void main(String[] args) {
  EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
      SpaceGame game = new SpaceGame();
      JFrame fr = new JFrame();
      fr.setTitle("SPACE GAME");
      // This is unadvisable :/
      fr.setSize(990, 690);
      fr.add(game);

      game.playingList.add(new Spaceship(3, 0, 570));
      game.playingList.add(new Spaceship(1, 250, 570));
      game.playingList.add(new Spaceship(2, 500, 570));

      JButton start = new JButton("START");
      start.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(java.awt.event.ActionEvent e) {
          game.start();
        }
      });
      fr.add(start, BorderLayout.SOUTH);

      fr.setVisible(true);
      fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
  });
}