i can't see circle moving

后端 未结 2 651
忘了有多久
忘了有多久 2021-01-29 05:26

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 ju

相关标签:
2条回答
  • 2021-01-29 05:28

    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.

    0 讨论(0)
  • 2021-01-29 05:47

    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.

    0 讨论(0)
提交回复
热议问题