【问题标题】:Java: Image , Graphics, and PanelJava:图像、图形和面板
【发布时间】:2018-08-26 08:20:32
【问题描述】:

我正在尝试使用 Java 制作动画,但无法理解 DoubleBufferImage 和 DoubleBufferGraphics。我了解 update()、render() 和 paint() 序列。但是,在每个方法中,我无法理解它是如何绘制的。这是代码。

  1. 游戏更新() // 我将跳过更新部分,因为我首先需要了解背景。

  2. 游戏渲染()

    private void gameRender() {
        if (DoubleBufferImage == null) {
            System.out.println("The Image is null: Error occurence");
            DoubleBufferImage = createImage(P_WIDTH - 15, P_HEIGHT - 15);
        }
    
        DoubleBufferGraphic = DoubleBufferImage.getGraphics();
    
        DoubleBufferGraphic.setColor(Color.LIGHT_GRAY);
        DoubleBufferGraphic.fillRect(0, 0, P_WIDTH, P_HEIGHT);
    
        DoubleBufferGraphic.setColor(Color.BLUE);
        DoubleBufferGraphic.setFont(font);
        DoubleBufferGraphic.drawString("Average FPS/UPS: " + 
                df.format(averageFPS) + df.format(averageUPS), 10, 10);
    }
    
  3. 绘画()

    public void paintScreen() {
        Graphics g;     
        try {           
            g = this.getGraphics();
            if ((g != null) && (DoubleBufferImage != null)) {               
                g.drawImage(DoubleBufferImage, 0, 0, null);         
            }           
            Toolkit.getDefaultToolkit().sync();     
        } catch (Exception e) {         
            System.out.println("Graphics context error: " + e);     
        }   
    }
    

还有从 Jpanel 覆盖的 paintComponent 方法。

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

这是我的问题。运行为更新->渲染->和绘画 但是,正如您从渲染中看到的那样,他们使用图形进行绘制。但这都是在 DoubleBufferImage 中绘制的吗? Image 实例是否类似于面板实例?我的意思是,它只是可添加到框架中吗? 由于这是双缓冲系统,所以我想知道哪些方法是直接绘制的,哪些是预先绘制的方法。 最后在运行中,没有代码表明我们制作的图像或图形将被添加到面板中。我只想知道绘制 BufferedImage 的时间。 请帮忙!我无法上传整个代码,所以我不确定你们是否能理解:(

【问题讨论】:

    标签: java swing


    【解决方案1】:

    好的,所以您似乎在反对一些错误信息和误解。也许你应该先看看paintComponent() vs paint() and JPanel vs Canvas in a paintbrush-type GUI

    在 AWT/Swing 中,至少有两种执行自定义绘制的方式,每种方式各有利弊。

    您可以使用paintComponent,它“挂钩”到 Swing 使用的绘画系统中。 Swing 使用“被动”渲染系统。这意味着您无法控制何时绘制某些内容,绘制系统会做出这些决定,然后(间接)调用组件的 paintComponent,以便您执行更新。

    另一种机制 (BufferStrategy) 使用“主动”渲染系统,让您可以完全控制何时进行绘制。

    作为一般规则,您不能混合使用它们。 Swing 有自己的绘画系统,不能很好地与BufferStrategy 配合使用,这意味着如果您想使用 Swing 组件作为输出的一部分,则不能。

    但这不会回答你的问题,或者不会直接

    让我们试着分解一下

    gameRender

    private void gameRender() {
        if (DoubleBufferImage == null) {
            System.out.println("The Image is null: Error occurence");
            DoubleBufferImage = createImage(P_WIDTH - 15, P_HEIGHT - 15);
        }
    
        DoubleBufferGraphic = DoubleBufferImage.getGraphics();
    
        DoubleBufferGraphic.setColor(Color.LIGHT_GRAY);
        DoubleBufferGraphic.fillRect(0, 0, P_WIDTH, P_HEIGHT);
    
        DoubleBufferGraphic.setColor(Color.BLUE);
        DoubleBufferGraphic.setFont(font);
        DoubleBufferGraphic.drawString("Average FPS/UPS: " + 
                df.format(averageFPS) + df.format(averageUPS), 10, 10);
    }
    

    此时,DoubleBufferImage 似乎是 BufferedImage,因此当调用 gameRender 时,它会检查是否存在缓冲区并根据需要创建它。然后它引用DoubleBufferImages Graphics 上下文并准备渲染,清除之前绘制的内容。

    Graphics 概览

    Graphics 是底层渲染管道顶部的抽象层,通常根据系统使用 OpenGL 或 DirectX 来实现。它提供了一个公共层,可以在该层上以独立于系统的方式执行图形操作

    paintScreen

    public void paintScreen() {
        Graphics g;     
        try {           
            g = this.getGraphics();
            if ((g != null) && (DoubleBufferImage != null)) {               
                g.drawImage(DoubleBufferImage, 0, 0, null);         
            }           
            Toolkit.getDefaultToolkit().sync();     
        } catch (Exception e) {         
            System.out.println("Graphics context error: " + e);     
        }   
    }
    

    这让我很担心,因为我没有上下文,但 this.getGraphics() 似乎引用了组件的 Graphics 上下文并将 DoubleBufferImage 绘制到它。

    这是危险的,不明智的。 getGraphics 返回组件上次绘制时的快照,可以在再次绘制组件时随时绘制。

    您应该尽早摆脱这种方法。

    paintComponent

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

    如上所述,paintComponent 是挂钩到 Swing 绘制系统的首选方法。所有这一切都是在绘制 DoubleBufferImage 它,尽管它实际上应该是 g.drawImage(DoubleBufferImage, 0, 0, this);

    那么,这一切在做什么?

    基本上,在 Swing 中执行双缓冲是不明智的尝试......默认情况下已经是双缓冲。

    但是,正如您从渲染中看到的那样,他们使用图形进行绘制。但这都是在 DoubleBufferImage 中绘制的吗? Image 实例和面板实例类似吗?

    没有。组件是一个对象,它具有许多属性。它的工作之一是绘制它的状态,这是通过各种绘制方法完成的,该方法传递一个 Graphics 上下文,该上下文附加到本地对等点,最终将呈现到屏幕(或打印机)。

    BufferedImage 就是这样一个图像。 Graphics 上下文只是一种简单的方法,您可以通过它来绘制它。然后可以将其保存到文件中,或者像这里的情况一样,绘制到组件(通过它的Graphics)上下文。

    正如我上面所说,Graphics 只是一个抽象层,它允许您对许多不同的目的地、屏幕、打印机、图像等执行绘画操作......

    我的意思是,它只是可添加到框架中吗?

    没有。它不是基于组件的类

    由于这是双缓冲系统,我想知道哪些方法是直接绘制,哪些是预先绘制的方法。

    paintComponent 和(不明智的)paintScreen 将图像直接绘制到组件上,最终由绘制子系统渲染到屏幕上。

    进一步阅读...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-04
      • 1970-01-01
      • 2012-11-27
      • 1970-01-01
      • 2012-02-12
      • 2016-07-13
      • 1970-01-01
      相关资源
      最近更新 更多