使用JFrame和JPanel的简单Java动画 [英] Simple Java Animation using JFrame and JPanel

查看:407
本文介绍了使用JFrame和JPanel的简单Java动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好,所以程序的目的是绘制并椭圆形并在屏幕上移动它.该代码在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();

        }
    }
}

解决方案

可能的问题是,线程对于UI而言运行太快,在球"离开可见区域后,UI显示良好. /p>

您需要做几件事...

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

有多种方法可以实现此目标,具体取决于您希望实现的目标,例如,您可以简单地使用Thread.sleep来使线程在两次更新之间暂停一小段时间.与此相关的问题是,Swing并不是线程安全的,并且应该在事件分派线程的上下文中对UI进行所有更新.

虽然编程很简单,但是在更新状态时可能会运行一次绘制循环,从而导致更新变脏.

另一种解决方案可能是使用Swing Timer,它可以让您定期安排在事件调度线程的上下文中触发的更新,从而使使用更加安全.

看看 Swing中的并发如何使用Swing计时器以获取更多详细信息.

作为一个例子...

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

    }

}

作为旁注,除非您确实有理由这样做,否则应避免覆盖paint,而应使用paintComponent

Ok, so the program's purpose is to just draw and oval and move it across the screen. The code compiles on Eclipse without an error, but when run, no oval is drawn or moved across the screen. I have been researching, and it seems that threads have to do a lot with this, but do I need one for this simple program? I am obviously new to GUI programming with Swing so I would appreciate an explanation or link to one for any additions to the program regarding threads or such related concepts.

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

        }
    }
}

解决方案

The likely problem is, that thread is running too fast for the UI, the UI is been shown well after the "ball" has left the visible area.

You need to do a couple of things...

First, you need to make sure that the updates are scheduled properly within the Event Dispatching Thread and secondly, that there is a short delay between updates. For example, 25fps is about a 40 millisecond delay between updates, 60fps is about 16 milliseconds

There are a number of ways to achieve this, depending what it is you hope to achieve, for example, you could simply use Thread.sleep to cause the thread to pause for a small amount of time between updates. The problem with this is Swing is not thread safe and all updates to the UI should be made within the context of the Event Dispatching Thread.

While you program is only simply, it's possible that a paint cycle could run while you updating it's state, resulting in a dirty update.

Another solution might be to use a Swing Timer which will allow you schedule updates at a regular interval which are triggered within the context of the Event Dispatching Thread, making it safer to use.

Have a look at Concurrency in Swing and How to use Swing Timers for more details.

As an example...

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

    }

}

As a side note, unless you really have reason to do so, you should avoid overriding paint and instead use paintComponent

这篇关于使用JFrame和JPanel的简单Java动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆