使用JFRAME和JPANEL的简单Java动画

发布于 2025-01-27 05:05:19 字数 838 浏览 3 评论 0原文

好的,该程序的目的是绘制和椭圆形,然后将其移动到屏幕上。该代码在日食上编译而不会出错,但是在运行时,没有绘制椭圆形或在屏幕上移动。我一直在研究,似乎线程必须对此做很多事情,但是我需要一个简单的程序吗?显然,我是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();

        }
    }
}

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

        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

メ斷腸人バ 2025-02-03 05:05:19

可能的问题是,对于UI而言,线程运行太快,在“球”离开可见区域后,UI得到很好的显示。

您需要做几件事...

首先,您需要确保更新在事件派遣线程中正确安排,其次,更新之间存在短延迟。例如,25FPS大约是更新之间的40毫秒延迟,60fps约为16毫秒,

有多种方法可以实现这一目标,具体取决于您希望实现的目标,例如,您可以简单地使用thread.sleep.sleep.sleep.sleep.sleep.sleep.sleep.sleep.sleep.sleep.sleep.使线程在更新之间暂停少量时间。问题的问题是摇摆不是线程安全的,并且应在事件派遣线程的上下文中对UI进行所有更新。

虽然您只是简单地编程,但在更新状态时,油漆周期可能会运行,从而导致肮脏的更新。

另一个解决方案可能是使用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();
        }

    }

}

作为旁注油漆,而是使用PaintComponent

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...

Moving Ball

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

夜光 2025-02-03 05:05:19

用睡眠来尝试您的循环,以适合您的代码。主实际上是线程。和jframe创建自己的线程。

while (true)
{
   game.moveBall();
   game.repaint();
   try { Thread.sleep(50); } catch (Exception e){}
}

我只是意识到,您不会用默认的颜色绘制整个屏幕。

将您的油漆方法更改为此

public void paint (Graphics g)
{
    super.paint(g);
    g.setColor(Color.white); //default color
    g.fillRect(0, 0, getWidth(), getHeight()); // fill whole canvas
    g.setColor(Color.black); //change color
    g.fillOval(x, y, 30, 30); // draw oval
}

try your loop with sleep as simplest way to fit your code. main is actually a thread. and JFrame creates its own thread.

while (true)
{
   game.moveBall();
   game.repaint();
   try { Thread.sleep(50); } catch (Exception e){}
}

and I just realized, you dont paint your whole screen with a default color.

change your paint method to this

public void paint (Graphics g)
{
    super.paint(g);
    g.setColor(Color.white); //default color
    g.fillRect(0, 0, getWidth(), getHeight()); // fill whole canvas
    g.setColor(Color.black); //change color
    g.fillOval(x, y, 30, 30); // draw oval
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文