摆动计时器未按预期执行

Timer of swing not performing as expected

我被建议不要使用 sleep 来暂停目的,而是使用 swing timer 但它仍然不是 working.The 我想要实现的动画是球移动从左上角斜向底部

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

class Show_starter {

    int x, y;
    JFrame window = new JFrame("Graphic_show");
    Graphic_panel jp = new Graphic_panel();

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

    private void go() {
        window.getContentPane().add(BorderLayout.CENTER, jp);
        window.setSize(600,800);
        window.setVisible(true);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    class Graphic_panel extends JPanel {

        public void paintComponent(Graphics g) {

            for ( int i = 0; i < 100; ++i) {
                g.setColor(Color.white);
                g.fillRect(0, 0, this.getWidth(), this.getHeight());
                g.setColor(Color.green);
                g.fillOval(x, y, 40, 40);

                x++;
                y++;

                try {

                    Timer tmr = new Timer(1000, new TimerListener()); //This fires an event after every 1 sec after it has started by start().
                   //But The ball travels too much fast and stops at a point and again travels very fast.
                    tmr.serRepeats(false); // even this is not working.
                    tmr.start();
                    //should i use repaint here or in Listener for this timer?
                } catch (Exception e){}
            }
        }

        class TimerListener implements ActionListener {

            public void actionPerformed(ActionEvent e) {
                jp.repaint();
            }
        }
    }
}

它表现出的行为是非常奇怪的球首先以非常高的速度移动并在一个点暂时停止然后再次以相同的速度移动。

我也曾尝试更改 timer 事件的触发时间,但同样的事情发生了。

即使在我开始的循环内部timer跟随函数调用也不起作用

setRepeats(false);

不要总是创建新的计时器,一个计时器就足够了。规定时间间隔多一点。1 秒对于一个 animation.you 来说太慢了,不需要循环,也不要在内部递增 x 和 y paintcomponet() 方法,因为此方法出于某种原因被调用,例如当您调整大小、最小化、最大化时。

意外行为是由于您的循环和创建新的 timers()。例如,在 x y 中从零开始,但在第一秒中 x y 增加到 100,100,在下一次绘制中你会看到它们处于 100,100 的位置。这看起来像是快速移动然后停止...

示例代码(已编辑)

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

public class Show_starter {

    private Timer tmr;

    int x, y;
    JFrame window = new JFrame("Graphic_show");
    Graphic_panel jp = new Graphic_panel();

    public static void main(String[] args) {

        Show_starter start = new Show_starter();
        start.go();

    }

    private void go() {

        window.getContentPane().add(BorderLayout.CENTER, jp);
        window.setSize(600, 800);
        window.setVisible(true);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        tmr = new Timer(10, new ActionListener() { // time gap in millisecond

            @Override
            public void actionPerformed(ActionEvent ae) {

                jp.increse();
                jp.repaint();
            }
        });
        tmr.start();

    }

    class Graphic_panel extends JPanel {

        public void increse() {
            x++;
            y++;
            if (x > 100) { // stop animation at x>100
                tmr.stop();
            }
        }

        public void paintComponent(Graphics g) {

            g.setColor(Color.white);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            g.setColor(Color.green);
            g.fillOval(x, y, 40, 40);

        }

    }
}

输出(比那个更流畅)

首先你不应该在 paint component.

中使用 loop
public void paintComponent(Graphics g){
            g.setColor(Color.white);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            g.setColor(Color.green);
            g.fillOval(x, y, 40, 40);
}

直接画出来,把xypublic放在class里面,这样就可以方便的从外面访问了

现在运行一个runnable(参考invokelaterswingUtilities)或者创建一个新的Thread

public void run() 里面做任何你想做的动画。您可以使用循环,但在每次迭代中添加 Thread.sleep(//in miliseconds)repaint() .

注意: 您需要更改 xy 以及 repaint() 以便在新位置绘制。并且需要 sleep() 来减慢执行速度,否则观众看不到它。