我看不到圆圈在移动

时间:2017-08-10 10:11:04

标签: java swing awt

在java中使用Swing时,我试图在单击按钮时将圆圈从起始位置缓慢移动到结束位置。但是,我无法看到圆圈在移动。它只是瞬间从头到尾移动。

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

我认为问题在于动作监听器,因为当我在不使用按钮的情况下这样做时,它正在工作。有什么建议吗?

2 个答案:

答案 0 :(得分:2)

正如Andrew Thompson所说,在没有定义第二个线程的情况下调用Thread.sleep()会冻结所有内容,因此解决方案是定义并运行另一个线程,如下所示:

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

}

此解决方案的唯一问题是多次按下按钮会加快圆圈的速度,但可以通过b.setEnabled(true/false)在动画期间使按钮不可点击来解决此问题。不是最好的解决方案,但它有效。

答案 1 :(得分:2)

如评论和另一个答案所述,请勿阻止EDT。 Thead.sleep(...)会阻止它,因此您有两种选择:

  • 创建和管理您自己的(新)主题。
  • 使用Swing Timer

在这个答案中,我将使用Swing Timer,因为它更容易使用。我还更改了paintComponent方法以使用Shape API并更改按钮文本以相应地启动和停止,以及为按钮和计时器重复使用相同的ActionListener

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

对不起,我不能发布我想要的GIF,但这个例子按预期运行。