用 Java 编程 Rain [英] Programming Rain in Java

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

问题描述

我是一名初级程序员,在高中学习 Java.我不是很好,但我喜欢编码,我想改进.在这段代码中,我只是想让雨粒子下落,但他们不会这样做.我也没有添加我的进口

I am a beginner programmer taking java in high school. I'm not very good but I love coding and I want to improve. In this code I'm simply trying to get rain particles to fall but they won't do so. Also I didn't add my imports

public class RainDrop
{

    private int x, y;
    private int width, height;
    private int vx;

    public RainDrop()
    {
        //x = (int) (Math.random()*640); 
        //y = (int) (Math.random() *500) - 500;
        x= (int) (Math.random()*640);
        y = 50;
        width = 3;
        height = 25;
        vx = 1;
    }
    public void draw(Graphics g)
    {
        g.setColor(Color.blue);
        g.fillRect(x, y, width, height);
    }
    public void fall()
    {
        y += vx;
        if(y >= 480)
        {
            y = (int) (Math.random() *500) - 500;
            vx = 1;

        }
    }

    public int getY()
    {
        return y;
    }
}



public class Panel extends JPanel implements Runnable

{

    public static final int drops = 1;
    public RainDrop[] d = new RainDrop[drops];
    public Panel()
    {
        for(int i = 0; i < drops; i++)
        {
            d[i] = new RainDrop();
        }
    }

    @Override
    public void run() 
    {
        update();
        repaint();
    }

    public void update()
    {
        for(int i = 0; i < drops; i++)
        {
            d[i].fall();
            repaint();
        }
    }

    public void paint(Graphics g)
    {
        for(int i = 0; i < drops; i++)
        {
            d[i].draw(g);
            repaint();
        }
    }
}



public class Runner extends JFrame
{

    public static void main(String[] args) 
    {

        JFrame obj = new JFrame();
        Panel j = new Panel();
        obj.setSize(640, 480);
        obj.setVisible(true);
        obj.setResizable(false);
        obj.setDefaultCloseOperation(EXIT_ON_CLOSE);
        obj.setTitle("Rain");
        obj.add(j);
        obj.setLocationRelativeTo(null);
    }
}

谁能帮帮我

推荐答案

您需要了解许多非常重要的主题

You have a number of very important topics you need to understand

首先是更好地了解绘画在 Swing 中的工作原理:

The first would be gaining a better understanding of how painting works in Swing:

您的代码中出现了两个主要问题:

Two main concerns crop up in your code:

  1. 覆盖paint(而不是调用super.paint).通常,不鼓励您直接覆盖 paint,而是优先覆盖 paintComponent(并确保按顺序调用 super.paintComponent保留已建立的油漆链)
  2. paint 中调用 repaint.这不是一个好主意,因为它会导致 UI 被绘制请求填满,增加 CPU 的压力并降低程序和系统的性能.
  1. Overriding paint (and not calling super.paint). Generally, you are discouraged from overriding paint directly, instead, preference is given to overriding paintComponent (and making sure you call super.paintComponent in order to preserve established paint chain)
  2. Calling repaint from within paint. This is not a good idea, as it can cause the UI to become saturated with paint requests, increasing the pressure on the CPU and degrading the perform of the program and system.

这会导致一些细微的修改,可能看起来像......

This leads to some slight modifications that might look something like...

public class Panel extends JPanel {

    public static final int drops = 1;
    public RainDrop[] d = new RainDrop[drops];

    public Panel() {
        for (int i = 0; i < drops; i++) {
            d[i] = new RainDrop();
        }
    }

    public void update() {
        for (int i = 0; i < drops; i++) {
            d[i].fall();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); 
        for (int i = 0; i < drops; i++) {
            d[i].draw(g);
            repaint();
        }
    }
}

接下来,您需要了解事件分派过程的工作原理以及 API 中应如何使用并发性.

Next, you need to gain some understanding into how the event dispatching process works and how concurrency should be used within the API.

Swing 中的并发开始.

简短版本是:

  • Swing 是单线程的
  • Swing 不是线程安全的

这意味着,你不应该在事件调度线程的上下文中执行任何长时间运行或阻塞的操作,而且,你也不应该从 EDT 的上下文之外更新 UI 或 UI 依赖的东西.

This means that, you should never perform any long running or blocking operations from within the context of the Event Dispatching Thread, but also, you should never update the UI or something the UI relies on from outside of the context of the EDT.

请记住,在绘画文档中,Swing 使用被动渲染方法.这意味着 Swing API 决定何时以及应该绘制什么,您只能提出建议,并且绘制可能随时发生,而您不知情或不输入.这使得 API 容易受到线程竞争条件的影响,并产生奇怪且难以复制的绘制问题.

Remember, from the painting documentation, Swing uses a passive rendering approach. This means that the Swing API makes decisions about when and what should be painted, you can only make suggestions, and that painting may occur at any time, without your knowledge or input. This makes the API susceptible to thread race conditions and generate weird and hard to replicate paint issues.

这将导致下一步.您需要某种方法来更新雨滴的状态并安排新的绘制周期,所有这些都必须以非阻塞方式完成,但可以安全地更新 UI 的状态.

This leads to the next step. You need some way to update the state of the rain drop(s) and schedule new paint cycles, all of which must be done in a none blocking manner but which can safely update the state of the UI.

最简单的解决方案是使用 Swing Timer

The simplest solution to this is using a Swing Timer

这会导致对 Panel 类的以下轻微修改...

This leads to following, slight, modification to the Panel class...

public class Panel extends JPanel {
    //...        
    public Panel() {
        //...            
        Timer timer = new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                update();
                repaint();
            }
        });
        timer.start();
    }
}

每 10 秒更新一次雨滴并安排新的绘制周期,从而提供核心"动画引擎.

Every 10th of a second, the rain drop is updated and new paint cycle is scheduled, thus providing the "core" animation engine.

我还建议对 Runner 类稍作修改...

I'd also recommend some slight modifications to the Runner class...

public class Runner {

    public static void main(String[] args) {
        new Runner();
    }

    public Runner() throws HeadlessException {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                JFrame obj = new JFrame();
                Panel j = new Panel();
                obj.setSize(640, 480);
                obj.setDefaultCloseOperation(EXIT_ON_CLOSE);
                obj.setTitle("Rain");
                obj.add(j);
                obj.setLocationRelativeTo(null);
                obj.setResizable(false);
                obj.setVisible(true);
            }
        });
    }
}

这做了很多事情...

  1. 删除 extends JFrame,因为您实际上并没有使用它,它只会混淆问题.此外,作为一般建议,您应该避免直接从顶级容器扩展,原因很多,但基本上,它会耦合您的代码并使其不灵活
  2. 将 UI 的创建移动到事件调度线程的上下文中
  3. 最后调用 setResiazablesetVisible,因为这会对 UI 显示(显示空白屏幕)产生不良影响 - Swing 的布局 API 是惰性的,因此除非您告诉它,否则它通常不会自行更新.
  1. Removes the extends JFrame, as you're not actually using it and it just confuses the issue. Also, as a general recommendation, you should avoid extending directly from top level containers, lots of reasons, but basically, it couples your code and makes it inflexible
  2. Moves the creation of the UI into the context of the Event Dispatching Thread
  3. Calls setResiazable and setVisible last, as this can have an undesirable affect on the UI when it's displayed (displaying a blank screen) - Swing's layout API is lazy, so unless you tell it, it won't generally update itself.

这篇关于用 Java 编程 Rain的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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