我有一个简单的小程序,可以沿画布的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();
}
}
的 的 ** * ** * **** 没有FLICKER的更新代码 * ** * ** * ***
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();
}
}
我使用此applet作为模板。
答案 0 :(得分: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
测试代码我的双缓冲概念是否有缺陷,或者是我的实施,还是两者兼而有之?
答案 1 :(得分: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
像素
velx
个像素
如果你这样做,你的动画会很流畅。
虽然计算可能非常具有挑战性,特别是当你的形状比一个正方形更复杂时/你的运动更复杂。这就是双缓冲的用武之地。
使用双缓冲,您可以创建与屏幕大小相同的内存中图像。你在那里画出你的整个主题。然后,您一次在屏幕上绘制该图像。
当这样做时,将不会有“整个屏幕是白色”的中间步骤;因此没有闪烁。但请注意,您最终会重新绘制整个屏幕,而不仅仅是更改的区域,这并不理想。考虑使用clipping - 一种重新绘制图像的预定义区域而不是整个图像的技术。
答案 2 :(得分:1)
问题是,像JApplet
这样的顶级容器不是双缓冲的。这意味着当它更新时,屏幕会闪烁,因为每个动作都直接在屏幕上完成。
相反,您应该使用类似JPanel
的内容创建自定义组件,并覆盖其paintComponent
方法并在那里执行自定义绘制操作。
由于Swing组件是双缓冲的,因此在将绘制操作绘制到屏幕之前缓冲绘制操作的结果,使其成为单个操作
请查看Performing Custom Painting了解详情