Starting animation with a button Java Swing










0















I'd like to create an animation of a few objects ("Spaceships") on the screen, with a start button. This is what I have so far:



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);






where:



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;






Of cousre the idea is that pressing the button would trigger the animation. The problem is that the animation would start automaticaly without the start button being pressed, and then when it ends, the button has no effect. How can I fix this?










share|improve this question






















  • Do not, ever, start a Timer in paintComponent, in fact, you should do NOTHING but paint the current state of the component in the paint methods. Instead, the Timer should be started by some other action, independently of the paint process

    – MadProgrammer
    Nov 14 '18 at 22:29











  • The other problem, as far as I can see is, the Timer and the button are using the same actionPerformed method, which doesn't make sense. Provide a method in your SpaceGame which can be called by the buttons ActionListener

    – MadProgrammer
    Nov 14 '18 at 22:31















0















I'd like to create an animation of a few objects ("Spaceships") on the screen, with a start button. This is what I have so far:



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);






where:



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;






Of cousre the idea is that pressing the button would trigger the animation. The problem is that the animation would start automaticaly without the start button being pressed, and then when it ends, the button has no effect. How can I fix this?










share|improve this question






















  • Do not, ever, start a Timer in paintComponent, in fact, you should do NOTHING but paint the current state of the component in the paint methods. Instead, the Timer should be started by some other action, independently of the paint process

    – MadProgrammer
    Nov 14 '18 at 22:29











  • The other problem, as far as I can see is, the Timer and the button are using the same actionPerformed method, which doesn't make sense. Provide a method in your SpaceGame which can be called by the buttons ActionListener

    – MadProgrammer
    Nov 14 '18 at 22:31













0












0








0








I'd like to create an animation of a few objects ("Spaceships") on the screen, with a start button. This is what I have so far:



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);






where:



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;






Of cousre the idea is that pressing the button would trigger the animation. The problem is that the animation would start automaticaly without the start button being pressed, and then when it ends, the button has no effect. How can I fix this?










share|improve this question














I'd like to create an animation of a few objects ("Spaceships") on the screen, with a start button. This is what I have so far:



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);






where:



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;






Of cousre the idea is that pressing the button would trigger the animation. The problem is that the animation would start automaticaly without the start button being pressed, and then when it ends, the button has no effect. How can I fix this?







java swing button jbutton






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 14 '18 at 22:22









Ramy LernerRamy Lerner

72




72












  • Do not, ever, start a Timer in paintComponent, in fact, you should do NOTHING but paint the current state of the component in the paint methods. Instead, the Timer should be started by some other action, independently of the paint process

    – MadProgrammer
    Nov 14 '18 at 22:29











  • The other problem, as far as I can see is, the Timer and the button are using the same actionPerformed method, which doesn't make sense. Provide a method in your SpaceGame which can be called by the buttons ActionListener

    – MadProgrammer
    Nov 14 '18 at 22:31

















  • Do not, ever, start a Timer in paintComponent, in fact, you should do NOTHING but paint the current state of the component in the paint methods. Instead, the Timer should be started by some other action, independently of the paint process

    – MadProgrammer
    Nov 14 '18 at 22:29











  • The other problem, as far as I can see is, the Timer and the button are using the same actionPerformed method, which doesn't make sense. Provide a method in your SpaceGame which can be called by the buttons ActionListener

    – MadProgrammer
    Nov 14 '18 at 22:31
















Do not, ever, start a Timer in paintComponent, in fact, you should do NOTHING but paint the current state of the component in the paint methods. Instead, the Timer should be started by some other action, independently of the paint process

– MadProgrammer
Nov 14 '18 at 22:29





Do not, ever, start a Timer in paintComponent, in fact, you should do NOTHING but paint the current state of the component in the paint methods. Instead, the Timer should be started by some other action, independently of the paint process

– MadProgrammer
Nov 14 '18 at 22:29













The other problem, as far as I can see is, the Timer and the button are using the same actionPerformed method, which doesn't make sense. Provide a method in your SpaceGame which can be called by the buttons ActionListener

– MadProgrammer
Nov 14 '18 at 22:31





The other problem, as far as I can see is, the Timer and the button are using the same actionPerformed method, which doesn't make sense. Provide a method in your SpaceGame which can be called by the buttons ActionListener

– MadProgrammer
Nov 14 '18 at 22:31












1 Answer
1






active

oldest

votes


















1














Let's start with the glaringly obvious...



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

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



Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.



You should have a look at Painting in AWT and Swing for more details about how painting works in Swing



Painting should simply paint the current state of the component and nothing else.



The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.



So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...



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);

);




Then update your main method to call it...



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);

);






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53309623%2fstarting-animation-with-a-button-java-swing%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Let's start with the glaringly obvious...



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

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



    Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.



    You should have a look at Painting in AWT and Swing for more details about how painting works in Swing



    Painting should simply paint the current state of the component and nothing else.



    The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.



    So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...



    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);

    );




    Then update your main method to call it...



    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);

    );






    share|improve this answer



























      1














      Let's start with the glaringly obvious...



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

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



      Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.



      You should have a look at Painting in AWT and Swing for more details about how painting works in Swing



      Painting should simply paint the current state of the component and nothing else.



      The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.



      So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...



      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);

      );




      Then update your main method to call it...



      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);

      );






      share|improve this answer

























        1












        1








        1







        Let's start with the glaringly obvious...



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

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



        Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.



        You should have a look at Painting in AWT and Swing for more details about how painting works in Swing



        Painting should simply paint the current state of the component and nothing else.



        The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.



        So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...



        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);

        );




        Then update your main method to call it...



        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);

        );






        share|improve this answer













        Let's start with the glaringly obvious...



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

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



        Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.



        You should have a look at Painting in AWT and Swing for more details about how painting works in Swing



        Painting should simply paint the current state of the component and nothing else.



        The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.



        So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...



        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);

        );




        Then update your main method to call it...



        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);

        );







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 14 '18 at 22:38









        MadProgrammerMadProgrammer

        301k17154269




        301k17154269





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53309623%2fstarting-animation-with-a-button-java-swing%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Barbados

            How to read a connectionString WITH PROVIDER in .NET Core?

            Node.js Script on GitHub Pages or Amazon S3