Java图形(2D)用于离屏渲染

3

我目前正在学习Java图形编程,并阅读安德鲁·戴维森(Andrew Davison)的《Java杀手级编程》。他编写了一个简单窗口应用程序,使用Image类进行离屏渲染,然后将图像复制到组件中。我觉得令人困惑的是,我们可以只创建图像,然后使用以下代码获取图形上下文:

dbg = dbImage.getGraphics();

我有点困惑,因为我们只使用dbg Graphics对象来绘制东西,但是后来我们在paintComponent方法中使用dbImage来显示我们画到dbg对象上的所有内容:
g.drawImage(dbImage, 0, 0, null);

那么,dbImage如何“知道”它包含了我们绘制到dbg Graphics对象上的所有图形内容呢?

以下是完整代码:

public class GamePanel extends JPanel implements Runnable{

    private static final int PWIDTH = 500;
    private static final int PHEIGHT = 400;

    private Thread animator;

    private volatile boolean running = false;

    private volatile boolean gameOver = false;

    private Graphics dbg;
    private Image dbImage = null;

    private Counter counter;

    public GamePanel(){
        setBackground(Color.white);
        setPreferredSize(new Dimension(PWIDTH, PHEIGHT));

        // create game components eg. counter.
        counter = new Counter(10);
        counter.start();
    }

    private void stopGame(){
        running = false;
    }

    @Override public void addNotify(){
        super.addNotify();
        startGame();
    }

    public void startGame(){
        if(animator == null || !running){
            animator = new Thread(this);
            animator.start();
        }
    }

    @Override
    public void run() {
        running = true;
        while(running){
            gameUpdate();
            gameRender();
            repaint();
            try{
                Thread.sleep(20);
            }
            catch(InterruptedException ex){
                // do something with the exception...
            }
        }
    }

    private void gameUpdate(){
        if(!gameOver){
            // update game state...
             if(counter.getCounter() == 0)
                 gameOver = true;

        }
    }

    private void gameRender(){
        if(dbImage == null){
            dbImage = createImage(PWIDTH, PHEIGHT);
            if(dbImage == null){
                System.out.println("dbImage is null");
                return;
            }       
            else
                dbg = dbImage.getGraphics(); // get graphics context for drawing to off-screen images.
        }

        // clear the background
        dbg.setColor(Color.white);
        dbg.fillRect(0, 0, PWIDTH, PHEIGHT);

        // draw game elements here...
        dbg.setColor(Color.black);
        dbg.drawString(Integer.toString(counter.getCounter()), 10, 10);

        if(gameOver)
            dbg.drawString("Game over...", 10, 20);
    }

    @Override public void paintComponent(Graphics g){
        super.paintComponent(g);
        if(dbImage != null)
            g.drawImage(dbImage, 0, 0, null);
    }
}

重要的部分只有paintComponent方法和gameRender()方法。


1
因为该Graphics实例是独立的,它属于图像而不属于其他任何东西。简单来说:Image实例保留对它的引用。(或者根据实现方式不同,也可能是相反的。但最终结果是相同的。) - biziclop
createImage方法将dbg和dbImage联系在一起,@biziclop?这背后是否有某种设计模式? - kimsay
1个回答

6
基本上,一个 Graphics 对象并不是你要在上面绘图的东西,而是你要用来绘画的东西。
当你调用 dbImage.getGraphics() 时,你就是在说“给我一个工具箱,让我可以在这张图片上画画”。在 Graphics 对象中的所有绘图方法都会在创建它的组件上绘制。它们不是在 Graphics 对象上绘制,而是在属于它的 Image 或 Component 上绘制。
把 Graphics 对象想象成调色板和画笔,把 Image 或 Component 想象成画布。
因此,当你完成了对 dbg 的操作后,就意味着你有了一幅充满彩色像素的图片,这个 Graphics 对象就是用它来绘制的。现在你可以将这个图片复制到另一个组件中,通过使用该组件的 Graphics 中的 drawImage 工具 - 它的 “工具箱”。

感谢 @RealSkeptic 的清晰回答。但这个技术上是如何工作的呢?getGraphics方法会以某种方式将Graphics和Image对象链接在一起吗? - kimsay
2
当然会受到影响。但是具体的实现方式取决于您拥有的组件/图像类型,因为每个像素点的“光栅”可以以不同的方式在内存中组织像素。因此,实际上getGraphics提供了一个专门为您正在使用的图像构建的自定义对象。它恰好继承自Graphics2D - RealSkeptic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接