为什么我的java动画占用了我的整个CPU

为什么我的java动画占用了我的整个CPU,java,swing,animation,Java,Swing,Animation,我制作了一个程序来显示光波的干涉图。我在JPanel上使用绘画方法绘制了两个源,然后围绕它们绘制同心圆。这将是双缝干涉,所以我允许其中一个光源四处移动,以实验狭缝宽度 问题是,当我运行这个时,我的计算机说它使用了我80%的CPU!其实没什么大不了的。在中间旋转,围绕它旋转,然后移动。我的代码如下 主要类别: import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.eve

我制作了一个程序来显示光波的干涉图。我在JPanel上使用绘画方法绘制了两个源,然后围绕它们绘制同心圆。这将是双缝干涉,所以我允许其中一个光源四处移动,以实验狭缝宽度

问题是,当我运行这个时,我的计算机说它使用了我80%的CPU!其实没什么大不了的。在中间旋转,围绕它旋转,然后移动。我的代码如下

主要类别:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;


public class main {
static final int UP = -1;
static final int DOWN = 1;
static final int RIGHT = 1;
static final int LEFT = -1;
static final int NOMOVEMENT = 0;


static int verticalMovement = NOMOVEMENT;
static int horizontalMovement = NOMOVEMENT;
public static void main(String[] args) {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    Point s1 = new Point((int)(screenSize.getWidth()/3), 50);
    Point s2 = new Point((int)(2*screenSize.getWidth()/3), 50);

    JFrame frame = new JFrame("Physics Frame");
    frame.setPreferredSize(screenSize);

    PhysicsPane pane = new PhysicsPane(screenSize, 15, s1, s2);
    pane.setPreferredSize(screenSize);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(pane);
    frame.pack();

    Timer time = new Timer(1000 / 20, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            switch (verticalMovement){
                case UP:
                    s2.changeY(UP);
                    break;
                case DOWN:
                    s2.changeY(DOWN);
                    break;
                default:
                    break;
            }
            switch (horizontalMovement){
                case RIGHT:
                    s2.changeX(RIGHT);
                    break;
                case LEFT:
                    s2.changeX(LEFT);
                    break;
                default:
                    break;
            }
            pane.repaint();
        }
    });

    frame.addKeyListener(new KeyListener() {
        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if(e.getKeyCode()==37){
                horizontalMovement = LEFT;
            } else if (e.getKeyCode()==38){
                verticalMovement = UP;
            } else if (e.getKeyCode()==39){
                horizontalMovement = RIGHT;
            } else if (e.getKeyCode()==40){
                verticalMovement = DOWN;
            }

            if(e.getKeyChar()=='a'){
                pane.setWaveLength(2);
            }
            if(e.getKeyChar()=='s'){
                pane.setWaveLength(-2);
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            switch (e.getKeyCode()){
                case 37:
                    horizontalMovement = NOMOVEMENT;
                    break;
                case 38:
                    verticalMovement = NOMOVEMENT;
                    break;
                case 39:
                    horizontalMovement = NOMOVEMENT;
                    break;
                case 40:
                    verticalMovement = NOMOVEMENT;
                    break;
            }
        }
    });
    frame.setVisible(true);
    time.start();

}
}
小组课。如果绘图方法效率低下,它就会出现在这里

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

public class PhysicsPane extends JPanel {
private Dimension size;
private Point[] pointArray = new Point[2];
private double waveLength;
public PhysicsPane(Dimension size, double wavelength, Point source1, Point source2) {
    this.size = size;
    pointArray[0] = source1;
    pointArray[1] = source2;
    setPreferredSize(size);
    this.waveLength = wavelength;
}

@Override
public void paintComponent(Graphics g){
    for (int i = 0; i < 2; i++) {
        g.setColor(Color.black);
        double x = this.pointArray[i].getX();
        double y = this.pointArray[i].getY();
        g.fillOval((int)x, (int)y, 2, 2);
        for (int j = (int)waveLength; j < 1500; j+=waveLength) {
            g.setColor(Color.red);
            g.drawOval((int)x-(j/2+1), (int)y-(j/2+1), 2 + j, 2 + j);
        }
    }
}

public void setWaveLength(double increment){
    this.waveLength+=increment;
}
}
那么我的程序有什么问题?为什么这么简单的动画占用了我这么多的处理器

更新代码部分:

@Override
public void paintComponent(Graphics g){
    BufferedImage bi = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
    Graphics graphics = bi.getGraphics();
    for (int i = 0; i < 2; i++) {
        graphics.setColor(Color.black);
        double x = this.pointArray[i].getX();
        double y = this.pointArray[i].getY();
        graphics.fillOval((int)x, (int)y, 2, 2);
        for (int j = (int)waveLength; j < 1500; j+=waveLength) {
            graphics.setColor(Color.red);
            graphics.drawOval((int)x-(j/2+1), (int)y-(j/2+1), 2 + j, 2 + j);
        }
    }
    g.drawImage(bi, 0, 0, new ImageObserver() {
        @Override
        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
            return false;
        }
    });
}
@覆盖
公共组件(图形g){
BuffereImage bi=新的BuffereImage(size.width、size.height、buffereImage.TYPE\u INT\u RGB);
Graphics=bi.getGraphics();
对于(int i=0;i<2;i++){
图形.设置颜色(颜色.黑色);
double x=this.pointArray[i].getX();
double y=this.pointArray[i].getY();
图形.椭圆形((int)x,(int)y,2,2);
对于(int j=(int)波长;j<1500;j+=波长){
图形.设置颜色(颜色.红色);
绘图椭圆((int)x-(j/2+1),(int)y-(j/2+1),2+j,2+j);
}
}
g、 drawImage(bi,0,0,新的ImageObserver(){
@凌驾
公共布尔图像更新(图像img、int-infoflags、int-x、int-y、int-width、int-height){
返回false;
}
});
}

我建议的改进是删除正在执行的不必要任务,特别是代码如何更新正在绘制的窗格,即使没有更改

以下更新将CPU使用率从12%降至0%(静态帧):


我不鼓励您使用
paint
并替代
paintComponent
。您还应该通过调用paint methods super Method来维护预期的绘画合同,我已经解决了这个问题。虽然它消耗的电量要少得多,但它仍然消耗了我CPU的1/2左右。这是动画制作的标准吗?你的绘画代码有很多,最好是生成一个屏幕外的缓冲区(<代码> BuffeReimeSea/Cudio>)。我还鼓励使用over
KeyListener
,这将解决潜在的焦点相关问题以及使用
KeyEvent.VK_LEFT
而不是37,因为它使您的意图更容易理解(我花了一些时间才找到键37),在运行代码时,我没有看到这种消耗,但您必须记住,Swing使用被动渲染算法,这意味着绘制可能会在任何时间出于任何原因发生,大多数情况下都没有您的知识或影响,因此可能需要额外的绘制周期。将问题全屏显示也意味着API有更大的区域需要尝试和更新。通常,blitting(绘制单个图像)比执行大量图形操作更快。在fastI中,我们已经能够在Swing中设置10000多个对象的动画,这并不是最好的性能,但它是可以做到的。如果你真的需要对绘画过程有更多的控制,请考虑一下
@Override
public void paintComponent(Graphics g){
    BufferedImage bi = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
    Graphics graphics = bi.getGraphics();
    for (int i = 0; i < 2; i++) {
        graphics.setColor(Color.black);
        double x = this.pointArray[i].getX();
        double y = this.pointArray[i].getY();
        graphics.fillOval((int)x, (int)y, 2, 2);
        for (int j = (int)waveLength; j < 1500; j+=waveLength) {
            graphics.setColor(Color.red);
            graphics.drawOval((int)x-(j/2+1), (int)y-(j/2+1), 2 + j, 2 + j);
        }
    }
    g.drawImage(bi, 0, 0, new ImageObserver() {
        @Override
        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
            return false;
        }
    });
}
Timer time = new Timer(1000 / 20, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {

        boolean refresh = false;

        switch (verticalMovement) {
        case UP:
            s2.changeY(UP);
            refresh = true;
            break;
        case DOWN:
            s2.changeY(DOWN);
            refresh = true;
            break;
        default:
            break;
        }

        switch (horizontalMovement) {
        case RIGHT:
            s2.changeX(RIGHT);
            refresh = true;
            break;
        case LEFT:
            s2.changeX(LEFT);
            refresh = true;
            break;
        default:
            break;
        }

        if (refresh == true) {
            pane.repaint();
        }
    }
});