2

我有一个简单的小程序,可以沿画布的 x 轴为矩形设置动画。问题是它闪烁。我试图用谷歌搜索这个问题,但我没有想出任何有用或我理解的东西。

我对 Java 比较陌生。

谢谢!

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*; 

public class simpleAnimation extends JApplet implements ActionListener { 
    Timer tm = new Timer(10, this); 
    int x = 0, velX = 2;

    public void actionPerformed(ActionEvent event) { 
        if (x < 0 || x > 550){ 
            velX = -velX; 
        }

        x = x + velX; 
        repaint(); 
    }

    public void paint ( Graphics g ) { 
    super.paint(g); 
    g.setColor(Color.RED); 
    g.fillRect(x, 30, 50, 30); 
    tm.start(); 
    } 
}

** * ** * ****更新后的代码没有闪烁* ** * ** * ***

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

public class simpleAnimation extends JApplet implements ActionListener  
{ 

     Graphics bufferGraphics; 

     Image offscreen; 

     Dimension dim; 

     int x = 3, velX = 2;

     Timer tm = new Timer(10, this);

     public void init()  
     { 

          dim = getSize(); 

          offscreen = createImage(dim.width,dim.height); 

          bufferGraphics = offscreen.getGraphics(); 
     }

      public void paint(Graphics g)  
     { 

          bufferGraphics.clearRect(0,0,dim.width,dim.width); 

          bufferGraphics.setColor(Color.red); 

          bufferGraphics.fillRect(x,50,50,20); 

          g.drawImage(offscreen,0,0,this); 

          tm.start();   

     }

     public void update(Graphics g) 
     { 

          paint(g); 

     } 

    public void actionPerformed(ActionEvent evt) 
    {   

        if ( x < 0 || x > 550){

            velX = -velX;

        }

        x = x + velX;   

        repaint();

    }

 }

我用这个小程序作为模板。

4

3 回答 3

3

我一直在为这种双缓冲的概念而苦恼。

这是我的示例,它覆盖了 JApplet 的paint() 和 JPanel 的 paintComponent(),默认情况下使用双缓冲。

我看不出明显的闪烁有任何区别。

//<applet code="SimpleAnimation.class" width="600" height="300"></applet>
import java.awt.*;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;

public class SimpleAnimation extends JApplet implements ActionListener {
    Timer tm = new Timer(10, this);
    int x = 0, velX = 2;
    JPanel panel;

    public void init()
    {
        panel = new JPanel()
        {
            @Override
            public Dimension getPreferredSize()
            {
                return new Dimension(50, 100);
            }

            @Override
            protected void paintComponent(Graphics g)
            {
                super.paintComponent(g);
                g.setColor(Color.RED);
                g.fillRect(x, 30, 50, 30);

            }
        };
        add(panel, BorderLayout.SOUTH);

        tm.start();
    }

    public void actionPerformed(ActionEvent event) {
        if (x < 0 || x > 550){
            velX = -velX;
        }

        x = x + velX;
        repaint();
//        panel.repaint();
    }

    public void paint ( Graphics g ) {
    super.paint(g);
    g.setColor(Color.RED);
    g.fillRect(x, 30, 50, 30);
    }
}

我使用以下代码测试代码:appletviewer SimpleAnimation.java

我的双缓冲概念有缺陷,还是我的实现有缺陷,或两者兼而有之?

于 2013-11-04T20:04:33.490 回答
1

你现在正在做的事情是这样的:

public void paint ( Graphics g ) {
  // draw the entire area white
  super.paint(g);
  g.setColor(Color.RED);
  // draw a rectangle at the new position
  g.fillRect(x, 30, 50, 30);
}

因此,每一步,您首先清除您的矩形,然后重新绘制它。因此闪烁 - 矩形下的像素不断从白色变为红色到白色到红色到白色到红色......

现在观察你需要做的最少的绘画是(假设矩形向右移动)这个:

  • velx在左边 WHITE 上绘制像素
  • 在右侧绘制velx像素 RED

如果你这样做,你的动画会很流畅。

但是,计算可能非常具有挑战性,尤其是当您的形状比正方形更复杂/您的动作更复杂时。这就是双缓冲的用武之地。

使用双缓冲,您可以创建与屏幕大小相同的内存图像。你在那里画你的整个主题。然后,您一次在屏幕上绘制该图像。

这样做时,不会有“整个屏幕都是白色的”的中间步骤;因此没有闪烁。但请注意,您最终会重新绘制整个屏幕,而不仅仅是更改的区域,这并不理想。考虑使用裁剪- 一种重新绘制图像的预定义区域而不是整个区域的技术。

于 2013-11-04T18:51:22.047 回答
1

问题是,像这样的顶级容器JApplet不是双缓冲的。这意味着当它更新时,屏幕会随着每个操作直接在屏幕上进行而闪烁。

相反,您应该创建一个自定义组件,使用类似 a 的东西JPanel,并覆盖其paintComponent方法并在那里执行您的自定义绘画操作。

因为 Swing 组件是双缓冲的,所以绘制动作的结果在它们被绘制到屏幕之前会被缓冲,使其成为单个动作

看看Performing Custom Painting了解更多细节

于 2013-11-04T19:37:49.797 回答