java applet:在两层2D场景中有一种简单的绘制和擦除方法吗?

我有一个applet,它使用圆和线显示一些数据。 随着数据不断变化,显示会更新,这意味着有时必须擦除圆圈和线条,所以我只是用白色(我的背景色)绘制它们以擦除它们。 (它们中有很多,所以擦除所有内容然后重新计算并重新绘制除擦除项目之外的所有内容将是一种非常慢的方法来擦除单个项目。)

情况的逻辑是需要显示两个层,我需要能够擦除一个层中的对象而不影响另一个层。 我认为上层需要具有“透明”的背景颜色,但是我将如何擦除对象,因为以透明颜色绘制无效。

这种情况与网络上所有与透明度相关的帮助的区别在于,我希望能够从透明层逐个擦除线条和圆圈,用“完全透明”的颜色覆盖它们的像素。

目前我的applet通过在start()中执行此操作来绘制(仅使用单个图层):

screenBuffer = createImage(640, 480); screenBufferGraphics = screenBuffer.getGraphics(); 

这在paint()中:

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

和对象通过以下命令呈现(或通过白色绘制“擦除”):

  screenBufferGraphics.drawLine(x1,y1,x2,y2); 

是否容易以某种方式制作具有透明背景的第二个屏幕缓冲区,然后能够在该缓冲区中绘制和擦除对象并将其渲染到第一个缓冲区上?

这似乎相当快,只要渲染图像区域保持在640×480左右,代码就可以达到125-165 FPS。 代码跟踪宽度为4px的2000条半透明线,并在与渲染图像大小相当的区域中移动它们。

弹跳线

 import java.awt.image.BufferedImage; import java.awt.event.*; import java.awt.geom.*; import java.awt.*; import javax.swing.*; import java.util.Random; class LineAnimator { public static void main(String[] args) { final int w = 640; final int h = 480; final RenderingHints hints = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); hints.put( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY ); final BufferedImage bi = new BufferedImage(w,h, BufferedImage.TYPE_INT_RGB); final JLabel l = new JLabel(new ImageIcon(bi)); final BouncingLine[] lines = new BouncingLine[20000]; for (int ii=0; ii1000 ) { lastTime = System.currentTimeMillis(); fps = count + " FPS"; count = 0; } g.setColor(Color.YELLOW); g.setFont(font); g.drawString(fps,10,30); l.repaint(); g.dispose(); } }; Timer timer = new Timer(1,al); timer.start(); JOptionPane.showMessageDialog(null, l); System.exit(0); } } class BouncingLine { private final Color color; private static final BasicStroke stroke = new BasicStroke(4); private static final Random random = new Random(); Line2D line; int w; int h; int x1; int y1; int x2; int y2; BouncingLine(int w, int h) { line = new Line2D.Double(random.nextInt(w),random.nextInt(h),random.nextInt(w),random.nextInt(h)); this.w = w; this.h = h; this.color = new Color( 128+random.nextInt(127), 128+random.nextInt(127), 128+random.nextInt(127), 85 ); x1 = (random.nextBoolean() ? 1 : -1); y1 = (random.nextBoolean() ? 1 : -1); x2 = -x1; y2 = -y1; } public void move() { int tx1 = 0; if (line.getX1()+x1>0 && line.getX1()+x10 && line.getY1()+y10 && line.getX2()+x20 && line.getY2()+y2 

更新1

当我发布该代码时,我认为你说的是​​100到1000,而不是1000到100,000! 在20,000线时,速率降至16-18 FPS左右。

更新2

..这种优化的方法,使用层,可能在Java?

当然。 我在DukeBox中使用了这种技术 - 它显示了它正在播放的声音的时髦情节。 它保留了许多缓冲图像。

  1. 背景。 非透明图像中的纯色。
  2. 老痕迹。 较旧的声音从原始位置伸展或褪色。 有透明度,允许BG显示。
  3. 最新追踪。 绘制在另外两个之上。 有透明度。

经过一天没有提出解决方案后,我开始认为Java Graphics无法将单个项目删除回透明色。 但事实certificate,改进的Graphics2D与BufferedImage和AlphaComposite一起提供了我正在寻找的function,允许我在各个层中绘制形状和擦除形状(回到完全透明)。

现在我在start()中执行以下操作:

  screenBuffer = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB); screenBufferGraphics = screenBuffer.createGraphics(); overlayBuffer = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB); overlayBufferGraphics = overlayBuffer.createGraphics(); 

我必须使用new BufferedImage()而不是createImage()因为我需要请求alpha。 (即使对于screenBuffer,虽然它是背景 – 去图!)我使用createGraphics()而不是getGraphics()只是因为我的变量screenBufferGraphics现在是Graphics2D对象而不仅仅是Graphics对象。 (虽然来回摆动也很好。)

paint()中的代码几乎没有区别:

  g.drawImage(screenBuffer, 0, 0, null); g.drawImage(overlayBuffer, 0, 0, null); 

并且像这样呈现(或擦除)对象:

 // render to background screenBufferGraphics.setColor(Color.red); screenBufferGraphics.fillOval(80,80, 40,40); // render to overlay overlayBufferGraphics.setComposite(AlphaComposite.SrcOver); overlayBufferGraphics.setColor(Color.green); overlayBufferGraphics.fillOval(90,70, 20,60); // render invisibility onto overlay overlayBufferGraphics.setComposite(AlphaComposite.DstOut); overlayBufferGraphics.setColor(Color.blue); overlayBufferGraphics.fillOval(70,90, 30,20); // and flush just this locally changed region repaint(60,60, 80,80); 

最终的Color.blue产生透明度,而不是蓝色 – 它可以是任何没有透明度的颜色。

最后要注意的是,如果你在AWT-EventQueue线程的不同线程中进行渲染(如果你花了很多时间渲染你也可能需要有一个响应接口),那么你需要同步上面的使用渲染例程在paint()中编写代码; 否则显示器会以半拉状态结束。

如果要在多个线程中进行渲染,则无论如何都需要同步渲染例程,以便Graphics2D状态更改不会相互干扰。 (或者也许每个线程都可以将自己的Graphics2D对象绘制到同一个BufferedImage上 – 我没试过。)

它看起来很简单,很难相信花了多长时间来弄清楚如何做到这一点!