简体   繁体   中英

i can't see circle moving

While using Swing in java, I am trying to move a circle slowly from a starting position to an end position when clicking a button. However, I can't see the circle moving. It just moves from start to end in an instant.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MyApp {

    private int x = 10;
    private int y = 10;
    private JFrame f;
    private MyDraw m;
    private JButton b;

    public void go() {
        f = new JFrame("Moving circle");
        b = new JButton("click me to move circle");
        m = new MyDraw();
        f.add(BorderLayout.SOUTH, b);

        f.add(BorderLayout.CENTER, m);
        f.setSize(500, 500);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);

        b.addActionListener(new Bute());
    }

    public static void main(String[] args) {
        MyApp m = new MyApp();
        m.go();
    }

    private class Bute implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            for (int i = 0; i < 150; i++) {
                ++x;
                ++y;
                m.repaint();
                Thread.sleep(50);
            }
        }
    }

    private class MyDraw extends JPanel {
        @Override
        public void paintComponent(Graphics g) {
            g.setColor(Color.white);
            g.fillRect(0, 0, 500, 500);
            g.setColor(Color.red);
            g.fillOval(x, y, 40, 40);
        }
    }
}

I think the problem is with the action listener because when I'm doing it without using button it is working. Any suggestions?

As Andrew Thompson said, calling Thread.sleep() without defining a second thread freezes everything, so the solution is to define and run another thread like so:

class Bute implements ActionListener, Runnable {
    //let class implement Runnable interface
    Thread t;   // define 2nd thread

    public void actionPerformed(ActionEvent e) {

        t = new Thread(this);   //start a new thread
        t.start();
    }

    @Override               //override our thread's run() method to do what we want 
    public void run() {     //this is after some java-internal init stuff called by start()
        //b.setEnabled(false);
        for (int i = 0; i < 150; i++) {
            x++;
            y++;
            m.repaint();
            try {
                Thread.sleep(50);   //let the 2nd thread sleep
            } catch (InterruptedException iEx) {
                iEx.printStackTrace();  
            }
        }
        //b.setEnabled(true);
    }

}

The only problem with this solution is that pressing the button multiple times will speed up the circle, but this can be fixed by making the button unclickable during the animation via b.setEnabled(true/false) . Not the best solution but it works.

As said in the comments and another answer, don't block the EDT. Thead.sleep(...) will block it, so you have two options:

  • Create and manage your own (new) thread.
  • Use a Swing Timer

In this answer I'll be using a Swing Timer , since it's easier to use. I also changed the paintComponent method to use the Shape API and change the button text to start and stop accordingly as well as reusing the same ActionListener for the button and the timer:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class MovingCircle {
    private JFrame frame;
    private CustomCircle circle;
    private Timer timer;
    private JButton button;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new MovingCircle()::createAndShowGui);
    }

    private void createAndShowGui() {
        frame = new JFrame(this.getClass().getSimpleName());
        circle = new CustomCircle(Color.RED);
        timer = new Timer(100, listener);
        button = new JButton("Start");
        button.addActionListener(listener);

        circle.setBackground(Color.WHITE);
        frame.add(circle);
        frame.add(button, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private ActionListener listener = (e -> {
        if (!timer.isRunning()) {
            timer.start();
            button.setText("Stop");
        } else {
            if (e.getSource().equals(button)) {
                timer.stop();
                button.setText("Start");
            }
        }
        circle.move(1, 1);
    });

    @SuppressWarnings("serial")
    class CustomCircle extends JPanel {
        private Color color;
        private int circleX;
        private int circleY;

        public CustomCircle(Color color) {
            this.color = color;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(color);
            g2d.fill(new Ellipse2D.Double(circleX, circleY, 50, 50));
        }

        @Override
        public Dimension preferredSize() {
            return new Dimension(100, 100);
        }

        public void move(int xGap, int yGap) {
            circleX += xGap;
            circleY += yGap;
            revalidate();
            repaint();
        }

        public int getCircleX() {
            return circleX;
        }

        public void setCircleX(int circleX) {
            this.circleX = circleX;
        }

        public int getCircleY() {
            return circleY;
        }

        public void setCircleY(int circleY) {
            this.circleY = circleY;
        }
    }
}

I'm sorry, I can't post a GIF as I wanted but this example runs as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM