使用JFrame和JPanel的简单Java动画

img*_*n62 1 java animation swing multithreading

好吧,所以程序的目的是绘制和椭圆形并在屏幕上移动它.代码在Eclipse上编译时没有错误,但是在运行时,不会在屏幕上绘制或移动椭圆.我一直在研究,似乎线程必须做很多事情,但是我需要一个这个简单的程序吗?我很明显是使用Swing进行GUI编程的新手,所以我很感激解释或链接到一个关于线程或相关概念的程序的任何添加.

public class Game extends JPanel
{
    int x =0;
    int y =0;

    private void moveBall()
    {

        x+=1;
        y+=1;
    }

    public void paint (Graphics g)
    {
        super.paint(g);
        g.fillOval(x, y, 30, 30);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Animation");
        Game game = new Game();
        frame.add(game);
        frame.setVisible(true);
        frame.setSize(300,400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        while (true)
        {
            game.moveBall();
            game.repaint();

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Mad*_*mer 5

可能的问题是,该线程对UI的运行速度太快,在"球"离开可见区域后,UI显示得很好.

你需要做几件事......

首先,您需要确保在事件调度线程中正确安排更新,其次,更新之间存在短暂的延迟.例如,25fps在更新之间约为40毫秒的延迟,60fps约为16毫秒

有许多方法可以实现这一点,具体取决于您希望实现的目标,例如,您可以简单地使用Thread.sleep以使线程在更新之间暂停一小段时间.这个问题是Swing不是线程安全的,所有对UI的更新都应该在Event Dispatching Thread的上下文中进行.

虽然编程只是简单,但是在更新状态时可能会运行一个绘制周期,从而导致更新脏.

另一个解决方案可能是使用Swing Timer,它允许您定期更新在事件调度线程的上下文中触发的更新,使其更安全.

查看Swing中的Concurrency如何使用Swing Timers获取更多详细信息.

举个例子...

移动球

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
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 BallAnimation {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new BallAnimation();
    }

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

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

    public class TestPane extends JPanel {

        private int x = 0;
        private int y = 0;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    moveBall();
                    repaint();
                }
            });
            timer.start();
        }

        protected void moveBall() {
            x++;
            y++;
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.fillOval(x, y, 30, 30);
            g2d.dispose();
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

作为旁注,除非你真的有理由这样做,否则你应该避免重写paint而是使用paintComponent