Peter
Peter

Reputation: 37

Java: Image , Graphics, and Panel

I am trying to make an animation by Java but having trouble understanding the DoubleBufferImage and DoubleBufferGraphics. I understand about the update(), render(), and paint() sequences. However, In the methods of each, I can't understand how it is being drawn. Here are the codes.

  1. gameUpdate() // I will just skip the updating part because I first need to understand the background.

  2. 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);
    }
    
  3. paint()

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

There's also paintComponent method which is overrided from Jpanel.

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

Here's my question. The running goes as update -> render -> and painting However as you can see from the render, they used graphics to draw. But is it all drawn in DoubleBufferImage? Is Image instance similar to panel instance? I mean, is it just addable to the frame? As this is the Double Buffering system, I want to know which methods is drawing directly, and which one is the method that draws beforehand. Finally in the running, there is no code that it's the Image or Graphics that we made are going to be added to the panel. I just want to know the timing that the BufferedImage is being drawn. Please help! I can't upload the whole code so I'm not sure if u guys can understand :(

Upvotes: 2

Views: 97

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347334

Okay, so you seem to be banging against some misinformation and misunderstandings. Perhaps you should start by having a look at something like paintComponent() vs paint() and JPanel vs Canvas in a paintbrush-type GUI

In AWT/Swing there are at least two ways of performing custom painting, each with there pros and cons.

You could use paintComponent, which a "hook" into the painting system used by Swing. Swing makes use of a "passive" rendering system. This means you don't have control of when something get's painted, the paint system makes those decisions and then calls (indirectly) the paintComponent of your component so you can perform the updates.

The other mechanism (BufferStrategy) uses a "active" rendering system, which gives you complete control over when painting occurs.

As a general rule, you can't mix them. Swing has it's own painting system and won't play well with BufferStrategy, so that means if you want to use Swing components as part of your output, you can't.

But that won't answer your question, or not directly

Let's try and break it down

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

At this moment in time, DoubleBufferImage seems to be a BufferedImage, so when gameRender is called, it checks to see if a buffer exists and creates it as needed. It then takes a reference of the DoubleBufferImages Graphics context and prepares it for rendering, cleaning off what was previously painted to it.

A quick overview of Graphics

Graphics is an abstract layer over the top of the underlying rendering pipeline, often implement using either OpenGL or DirectX depending on the system. It provides a common layer onto which graphics operations can be performed in a system independent manner

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 worries me, as I have no context, but this.getGraphics() seems to be taking a reference of a component's Graphics context and drawing the DoubleBufferImage to it.

This is dangerous and ill advised. getGraphics returns a snapshot of the component from when it was last painted, which could be painted over at anytime when the component is painted again.

You should, at the earliest opportunity, get rid of this method.

paintComponent

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

As mentioned above, paintComponent is the preferred method for hooking into the paint system of Swing. All this does is paints the DoubleBufferImage it, although it should actually read g.drawImage(DoubleBufferImage, 0, 0, this);

So, what is all this doing?

Basically, it's an ill-advised attempt to perform double buffering in Swing ... which is already double buffered by default.

However as you can see from the render, they used graphics to draw. But is it all drawn in DoubleBufferImage? Is Image instance similar to panel instance?

No. A component is an object, which has a number of properties. One of it's jobs is to paint it's state, which is done via the various paint methods, which is passed a Graphics context which is attached to a native peer and eventually will be rendered to the screen (or printer).

A BufferedImage is just that, an image. The Graphics context is just a simple means by which you can paint to it. It can then be saved to a file or, as is the case here, painted to a component (via it's Graphics) context.

As I said above, Graphics is just an abstract layer, which allows you to perform painting operations to a number of different destinations, screen, printers, images, etc...

I mean, is it just addable to the frame?

No. It's not a component based class

As this is the Double Buffering system, I want to know which methods is drawing directly, and which one is the method that draws beforehand.

paintComponent and (the ill-advised) paintScreen are painting the image directly to the component, which will, eventually be rendered to the screen by the painting sub system.

Further reading...

Upvotes: 1

Related Questions