How to move a circle automatically in java? [close

2019-06-14 18:41发布

问题:

I am new to java GUI, and am trying to learn it. I want to move a circle on screen automatically(i.e not by pressing any key or doing any other action). I found a way to move it by doing some action but thats not what i needed. Please could anybody tell me the simplest way of doing that?

I want to remove the action listener in the following code, so that circles move automatically:

public class MyFirstGraphics extends JFrame {

    int x = 100;
    int y = 100;

    MyFirstGraphics() {
        super("Circle");
        setSize(800, 800);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setBackground(Color.pink);
        JButton f = new JButton("circle");
        f.addActionListener(new re());
        add(f, BorderLayout.NORTH);
    }

    private class re implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            for (int i = 1; i < 50; i++) {
                x++;
                y++;
                repaint();
            }
        }
    }

    public void paint(Graphics g) {
        super.paint(g);
        g.drawOval(x, y, 100, 100);
    }

    public static void main(String[] args) {
        MyFirstGraphics l = new MyFirstGraphics();
        l.setVisible(true);
    }
}

回答1:

Lets start with the fact that animation is the illusion of change over time. Also, Swing is a single threaded environment. You can't "block" the Swing thread (aka the Event Dispatching Thread) and have it paint updates, you need some way to schedule updates at a regular bases so you can apply a change and then have the change repainted...

So your first problem is in your actionPerformed method...

for (int i = 1; i < 50; i++) {
    x++;
    y++;
    repaint();
}

Basically, the only thing that will get painted is the ball at 150x150, nothing else in between will be painted.

Instead, you need to change it to something more like...

public void actionPerformed(ActionEvent e) {
    if (x < 150 && y < 150) {
        x++;
        y++;
    } else {
        ((Timer)e.getSource()).stop();
    }
    repaint();
}

Take a look at:

  • Performing Custom Painting
  • 2D Graphics
  • Concurrency in Swing
  • How to Use Swing Timers

For more details

A basic "bouncy" ball example

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class BounceyDot {

    public static void main(String[] args) {
        new BounceyDot();
    }

    public BounceyDot() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int x = 0;
        private int y = 100;
        private int radius = 20;
        private int xDelta = 2;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    x += xDelta;
                    if (x + (radius * 2) > getWidth()) {
                        x = getWidth() - (radius * 2);
                        xDelta *= -1;
                    } else if (x < 0) {
                        x = 0;
                        xDelta *= -1;
                    }
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.fillOval(x, y - radius, radius * 2, radius * 2);
        }
    }

}


回答2:

To animate that code, use a Swing based Timer with the re ActionListener as one argument in the constructor (the other argument is the delay).

See How to Use Swing Timers for details and working examples.