问题描述
我有一个小程序,它使用圆圈和线条显示一些数据.随着数据的不断变化,显示也会更新,这意味着有时必须擦除圆圈和线条,所以我只是将它们绘制为白色(我的背景颜色)以将其擦除.(它们有很多,因此擦除所有内容然后重新计算并重新绘制除已擦除项目之外的所有内容将是擦除单个项目的极其缓慢的方式.)
I have an applet which displays some data using circles and lines. As the data continually changes, the display is updated, which means that sometimes the circles and lines must be erased, so I just draw them in white (my background color) to erase them. (There are a lot of them, so erasing everything and then recomputing and redrawing everything except the erased item would be a horribly slow way to erase a single item.)
情况的逻辑是有两层需要显示,我需要能够擦除一层中的对象而不影响另一层.我想上层需要有一个透明"的背景颜色,但是我将如何擦除一个对象,因为以透明颜色绘制没有效果.
The logic of the situation is that there are two layers that need to be displayed, and I need to be able to erase an object in one layer without affecting the other layer. I suppose the upper layer would need to have a background color of "transparent", but then how would I erase an object, since drawing in a transparent color has no effect.
这种情况与网络上所有与透明度相关的帮助的区别在于,我希望能够从透明层中一个一个地擦除线条和圆圈,用完全透明"颜色覆盖它们的像素.
What distinguishes this situation from all the transparency-related help on the web is that I want to be able to erase lines and circles one-by-one from the transparent layer, overwriting their pixels with the "fully transparent" color.
目前我的小程序通过在 start() 中执行此操作来绘制(仅使用单个图层):
Currently my applet draws (using just a single layer) by doing this in start():
screenBuffer = createImage(640, 480);
screenBufferGraphics = screenBuffer.getGraphics();
在paint()中:
g.drawImage(screenBuffer, 0, 0, this);
并且对象通过以下命令呈现(或通过以白色绘制擦除"):
and objects are rendered (or "erased" by drawing in white) by commands like:
screenBufferGraphics.drawLine(x1,y1,x2,y2);
是否容易以某种方式制作具有透明背景的第二个屏幕缓冲区,然后能够在该缓冲区中绘制和擦除对象并将其渲染到第一个缓冲区上?
Is it easy to somehow make a second screen buffer with a transparent background and then be able to draw and erase objects in that buffer and render it over the first buffer?
推荐答案
在没有提出解决方案的一天之后,我开始认为 Java Graphics 无法将单个项目擦除回透明颜色.但事实证明,改进后的 Graphics2D 与 BufferedImage 和 AlphaComposite 一起提供了几乎完全符合我的要求的功能,允许我在各个图层中绘制形状和擦除形状(恢复为完全透明).
After a day of no proposed solutions, I started to think that Java Graphics cannot erase individual items back to a transparent color. But it turns out that the improved Graphics2D, together with BufferedImage and AlphaComposite, provide pretty much exactly the functionality I was looking for, allowing me to both draw shapes and erase shapes (back to full transparency) in various layers.
现在我在 start() 中执行以下操作:
Now I do the following in 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 对象.(虽然来回投射也很好.)
I have to use new BufferedImage()
instead of createImage()
because I need to ask for alpha. (Even for screenBuffer, although it is the background -- go figure!) I use createGraphics()
instead of getGraphics()
just because my variable screenBufferGraphics is now a Graphics2D object instead of just a Graphics object. (Although casting back and forth works fine too.)
paint() 中的代码几乎没有什么不同:
The code in paint() is barely different:
g.drawImage(screenBuffer, 0, 0, null);
g.drawImage(overlayBuffer, 0, 0, null);
对象被渲染(或擦除)如下:
And objects are rendered (or erased) like this:
// 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 产生透明度,而不是蓝色——它可以是任何没有透明度的颜色.
The final Color.blue yields transparency, not blueness -- it can be any color that has no transparency.
最后要注意的是,如果您在与 AWT-EventQueue 线程不同的线程中进行渲染(如果您花费大量时间进行渲染,但还需要具有响应式界面,则可能是这种情况),那么您将需要将paint()中的上述代码与您的渲染例程同步;否则显示屏可能会处于半绘制状态.
As a final note, if you are rendering in a different thread from the AWT-EventQueue thread (which you probably are if you spend a lot of time rendering but also need to have a responsive interface), then you will want to synchronize the above code in paint() with your rendering routine; otherwise the display can wind up in a half-drawn state.
如果您在多个线程中渲染,则无论如何都需要同步渲染例程,以便 Graphics2D 状态更改不会相互干扰.(或者,也许每个线程都可以将自己的 Graphics2D 对象绘制到同一个 BufferedImage 上——我没有尝试这样做.)
If you are rendering in more than one thread, you will need to synchronize the rendering routine anyway so that the Graphics2D state changes do not interfere with each other. (Or maybe each thread could have its own Graphics2D object drawing onto the same BufferedImage -- I didn't try that.)
看起来很简单,很难相信花了多长时间才弄清楚如何做到这一点!
It looks so simple, it's hard to believe how long it took to figure out how to do this!
这篇关于java小程序:有没有一种简单的方法可以在两层2D场景中进行绘制和擦除?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!