为什么我的java动画占用了我的整个CPU
我制作了一个程序来显示光波的干涉图。我在JPanel上使用绘画方法绘制了两个源,然后围绕它们绘制同心圆。这将是双缝干涉,所以我允许其中一个光源四处移动,以实验狭缝宽度 问题是,当我运行这个时,我的计算机说它使用了我80%的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
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>)。我还鼓励使用overKeyListener
,这将解决潜在的焦点相关问题以及使用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();
}
}
});