Java Tips Weblog

  • Blog Stats

    • 2,530,130 hits
  • Categories

  • Archives

Custom Painting Approaches

Posted by Rob Camick on May 8, 2009

The basics of custom painting are explained in the section from the Swing tutorial on Custom Painting (see link below). The main idea is that you can customize a component by overriding its paintComponent() method. Typically, JComponent or JPanel will be overridden to do custom painting. A concern of many people is adding too much painting code to the paintComponent method which might result in excessive CPU usage or slow painting. Is this a valid concern and if so, then is there anything that can be done to minimize these problems?

First, lets look at the normal approach of painting which I’m going to refer to as “active” painting for the purposes of this blog. I call this “active” because painting is done directly on the component from scratch every time the paintComponent() method is invoked. Typically you would store information about the object to be painted in a List. Then, whenever the paintComponent() method is invoked you would iterate through the List and paint each object. Some advantages of this approach:

  • easy to use as all the painting code is contained in one place
  • allows for easy changing of the painting (ie. animation)
  • allows for easy undo of existing painting
  • the painting area can dynamically change in size

Some drawbacks of this approach:

  • extra overhead to repaint the objects every time. Will this overhead be noticeable? I wouldn’t worry about this unless you notice a problem.

I’m going to refer to the following alternative approach to painting as the “passive” approach. This is because the “active” painting will be done to a BufferedImage as required. Then, the paintComponent() method, whenever it is invoked, will “passively” draw the BufferedImage onto the component. Some advantages of this approach:

  • should be slightly faster painting. The relative performance increase will depend on the complexity of the painting.

Some drawbacks of this approach:

  • slightly harder to use as you need to create the BufferedImage and manage the painting to it
  • painting is done in multiple places
  • harder to undo painting
  • the painting area is fixed in size

The best way to understand the differences between the two approaches is to look at code and see each approach in action, so I have included code for each approach below. The functionality of each class is the same and attempts to address “how to”:

  • do static painting, in this case, by drawing a line of text.
  • change the painting dynamically, in this case, by adding rectangles of a different color.
  • reset the painting to its original state.

The differences between each approach are contained in the following three methods:

  • paintComponent – responsible for the custom painting whenever repaint is invoked on the panel. For the active approach you need to draw the static text and loop through the list to paint all the rectangles. For the passive approach you simply draw the buffered image.
  • addRectangle – responsible for adding the dynamic rectangles. For the active approach you just add a rectangle to the list. For the passive approach you draw the rectangle on the buffered image right away.
  • clear – responsible for resetting the panel to its initial state. For the active approach you just clear the list. For the passive approach you need to recreate (or clear) the buffered image and then draw the static text.

Take the time to understand the code differences in each of the above methods and hopefully you will understand the differences in the two approaches.

Now, for fun, while using each of the programs try to duplicate my happy face drawing from the image below:

Custom-Painting-Approaches

Did you notice any performance difference between either of the programs? I doubt you will. It has been my experience that you would need to draw hundreds or thousands of rectangles before you would notice any difference. Therefore my suggestion would be to start with the normal or “active” approach to painting. Then, if you experience a problem you can switch to the alternate or “passive” approach of using a BufferImage.

If you want to have move fun try adding animation to each program. Something simple like randomly changing the location of each rectangle.

Get The Code

DrawOnComponent.java (Active)
DrawOnImage.java (Passive)

Related Reading

Java Tutorials: Performing Custom Painting
Java Tutorials: 2D Graphics

Advertisement

7 Responses to “Custom Painting Approaches”

  1. Andre Uhres said

    For better performance with complicated components, “smart painting” could additionally be applied to both “active” and “passive” painting. Smart painting tries to use clip information to restrict painting to a smaller rectangle (Graphics#getClipBounds), instead of always painting the whole component. This requires the use of the “multi arguments” version of the repaint method, defining the rectangle to be updated.

    • Rob Camick said

      Yes, that would probably be better covered in an advance painting tutorial. Actually I plan on releasing a “LineNumber” component that can be used with a text area or text pane. So for a simple example of “smart painting” check back in a week or two.

      In general, I would still recommend you don’t worry about optimization until it is a problem.

  2. Anonymous said

    Nice

  3. Robocop said

    how to draw a circle and a rectangle in the same component

    • Rob Camick said

      This idea of this blog entry was to show the two different painting approaches. For your requirement, the easiest approach would probably be to change the DrawOnImage example. First you would need to add a couple components, maybe JRadioButtons (for Rectangle, Oval). Then in the painting code, you need to check to see with radio button is selected. Then you would use drawRect(…) or drawOval(…).

  4. Tiago Correia said

    Hi there,

    I’m using the paint function to paint some rectangles that are defined on text boxes outside the painting.

    But, each time that the user change some parameter I want it to clear and repaint the rectangles with the new definitions.

    Could you help me with that?

    • Rob Camick said

      I suggest you use a JLabel with a LineBorder. If you need more help then ask your question in a forum where you can provide more information along with your current code demonstrating the problem.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: