How Does Paintcomponent Work

How does paintComponent work?

The (very) short answer to your question is that paintComponent is called "when it needs to be." Sometimes it's easier to think of the Java Swing GUI system as a "black-box," where much of the internals are handled without too much visibility.

There are a number of factors that determine when a component needs to be re-painted, ranging from moving, re-sizing, changing focus, being hidden by other frames, and so on and so forth. Many of these events are detected auto-magically, and paintComponent is called internally when it is determined that that operation is necessary.

I've worked with Swing for many years, and I don't think I've ever called paintComponent directly, or even seen it called directly from something else. The closest I've come is using the repaint() methods to programmatically trigger a repaint of certain components (which I assume calls the correct paintComponent methods downstream.

In my experience, paintComponent is rarely directly overridden. I admit that there are custom rendering tasks that require such granularity, but Java Swing does offer a (fairly) robust set of JComponents and Layouts that can be used to do much of the heavy lifting without having to directly override paintComponent. I guess my point here is to make sure that you can't do something with native JComponents and Layouts before you go off trying to roll your own custom-rendered components.

How to make the paintComponent method work?

You need two additions in main method for this to work. You have to instantiate the MyDrawPanel() class and then add it to the frame.

MyDrawPanel p = new MyDrawPanel();

and

frame.add(p);

So the main method should be:

    public static void main(String[] args) {
JFrame frame = new JFrame();
MyDrawPanel p = new MyDrawPanel();

frame.add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}

What is the JPanel/Graphics method paintComponent?

Why is paintComponenet used twice, for the name of the method and as we call a method from super (JPannel)

It's not "used" twice. It is overridden once, but you want to call the parent (JPanel) class's super method so that you're sure that it does its own house-keeping painting, including painting its children and clearing out any dirty bits from the screen.

What is Graphics g, isn't it just a reference variable for an object of Graphics since we don't set it equal to = new Graphics();

It's a Graphics parameter. You don't set it = new Graphics() because the JVM does this for you. It calls the method behind the scenes when needed, and provides the parameter.

Why does the method name in my class have to be paintComponent to call upon the method paintComponent from JPannel or super

It has to override the super's method so that the JVM calls the right method when it wants to draw the GUI.

The method in my class paintComponent takes the parameter of a Graphics object but when does paintComponent even get called and when is the parameter of Graphics inserted.

Again, it is called by the JVM when either your program wants to repaint the GUI, such as when you call repaint() or when the operating system wants to repaint a window such as if a window is minimized and restored.

You really really want to read the graphics tutorials:

  • Lesson: Performing Custom Painting: introductory tutorial to Swing graphics
  • Painting in AWT and Swing: advanced tutorial on Swing graphics

What does super.paintComponent(g) do?

  1. What does it do?

It prints the component as if you hadn't overridden the paintComponent method. If you have a background color set for instance, this is typically painted by the class you're extending.


  1. When do we need to use it?

You use it if you don't paint on the entire component. The parts that you don't paint will "shine through" which means that you should let the super class paint those parts. As with the example of the background color for instance: If you just paint a circle in the middle of the component, super.paintComponent will make sure the background color is painted around the circle.

If you do paint the entire area of your component, then you will paint on top of whatever super.paintComponent paints and thus there's no point in calling super.paintComponent.


  1. What advantage does it gives us by writing it in paintComponent()?

That's the only logical place to put it. paintComponent is called when the component should be painted, and, as mentioned above, if you don't paint the entire component yourself, you need super.paintComponent to paint on the parts that shine through.

The documentation of paintComponent says it pretty well:

[...] if you do not invoker super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts.

Why does one have to use the paintComponent method to draw in Java?

That's because that's the way it works. It was designed this way. But I guess your question is about "why"

Remember, Swing first came out nearly 15 years ago. One of the criticisms was that the API was slow (the fact was, it was slow because people didn't truly understand how to use it, but that's another story), so the API had to be designed with performance in mind.

There are a number of factors involved...

Swing uses a passive paint process, meaning that the paint requests are made to the paint sub system and schedule (back on the EDT) for processing. The paint sub system makes decisions about what, when and how much should be painted. This is done at the desecration of the paint sub system.

This means that you never really know when a paint cycle may be executed, so we need some way to be able to respond to these requests.

Versatility is another factor. The API is abstract enough that it doesn't matter (a lot), where the component is being painted to. That is, you could be being painted to the screen, printer or even a image. This means you don't have to repeat a lot of paint code to make it work on different devices.

You also never know when a component will become displayable (that is, when it becomes attached to a native peer). This means that the graphics context may be null, so having "helper" methods may actually cause more problems. When paintComponent is called, you are (mostly) guaranteed to have a valid graphics context to paint to.

Extendability would be another factor. Not only is it very easy to override the paintComponent to alter the way some component paints, it's also possible for the paint system to provide a extended Graphics context, as is the current case. When paintComponent is called (by the paint sub system at least), it guarantees that the Graphics context will be an instance of Graphics2D, which is an extension to Graphics, providing a number of important enhancements to the API.

This is all done without the need to change the base class which people are using, so if they don't want to use these features, they remain unaffected by them.

You may want to take a read through...

  • Painting in AWT and Swing
  • Passive vs. Active Rendering

For more details

And remember "Painting is fun" ;)

Additional Thoughts

One of the other considerations to take into account is the fact the the Graphics API is central to painting, not just with consideration to the UI, but also printing and image manipulation. The API is disconnected from it's target, allowing a greater deal of flexibility, but also commonality.

This means that if you need to print to a printer or render to an image, you can use the same API you would for painting to the screen.



Related Topics



Leave a reply



Submit