Java小程序:有一个简单的方法来绘制和擦除的两层2D的场景?方法来、两层、有一个、场景

2023-09-07 13:44:33 作者:鱼

我用圆圈和线,显示一些数据的小程序。随着数据不断变化,更新显示内容,这意味着有时圆和线必须被删除,所以我只是把它们画在白色(我的背景色)来清除它们。 (有很多人,所以删除一切,然后重新计算和重绘以外的所有被删除的项目将是一个可怕的缓慢的方式来删除一个单一的项目。)

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.

目前我的小程序绘制(只用单层)在开始这样做():

Currently my applet draws (using just a single layer) by doing this in start():

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

这在paint()方法:

and this in 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图形无法抹去个别项目回一个透明的颜色。但事实证明,改进后的Graphics2D,与BufferedImage中和的AlphaComposite在一起,提供pretty的多正是我一直在寻找的功能,让我既绘制形状和消除形状(回完全透明)的各层。

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.

现在我做的在开始后():

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();

我必须使用新的BufferedImage(),而不是中的createImage(),因为我要问的阿尔法。 (即使是screenBuffer,虽然它的背景是 - 去图)我用的createGraphics()而不是的getGraphics()只是因为我的变量screenBufferGraphics现在是一个Graphics2D对象,而不是只是一个图形对象。 (虽然铸造来回正常工作了。)

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.)

在code油漆()仅仅是不同的:

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中的线程不同的线程(你可能是,如果你花了很多时间渲染,但还需要有一个负责任的接口),那么你将要同步以上code油漆()与你的渲染程序;否则,显示器可以在一个半牵伸状态拉闸。

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!