Search code examples
javaswingpaintgraphics2dtablecellrenderer

Optimizing a jtable


I've created a TableCellRenderer out of a JLabel whose paint() is somewhat heavy, mostly bacause of a g2d.drawString() which is given a utf string. The problem is that this paint() is very repeatedly called, within the following stack:

MultiTableCellRenderer$TableHeaderLabel.paint:235   
CellRendererPane.paintComponent:151 
BasicTableUI.paintCell:2115 
BasicTableUI.paintCells:2016    
BasicTableUI.paint:1812 
ComponentUI.update:161  
JComponent.paintComponent:780   
JComponent.paint:1056   
JComponent.paintChildren:889    
JComponent.paint:1065   
JViewport.paint:728 
JComponent.paintChildren:889    
JComponent.paint:1065   
JComponent.paintChildren:889    
JComponent.paint:1065   
JComponent.paintChildren:889    
JComponent.paint:1065   
JComponent.paintChildren:889    
JSplitPane.paintChildren:1047   
JComponent.paint:1065   
JComponent.paintToOffscreen:5219    
RepaintManager$PaintManager.paintDoubleBuffered:1572    
RepaintManager$PaintManager.paint:1495  
RepaintManager.paint:1265   
JComponent._paintImmediately:5167   
JComponent.paintImmediately:4978    
RepaintManager$4.run:824    
RepaintManager$4.run:807    
AccessController.doPrivileged   
....

How can this repeating process be prevented? I've checked the DefaultTableCellRenderer implementation, and saw that they have overriden many of the methods, such as repaint(), revalidate() etc. replacing most of them with empty methods to enhance performance. I also did so, and it did help, but yet the greater part of the problem is staying there. At least about 10% of my CPU is constantly consumed by this very paint() method, and the entire application has been seriously slowed down. Any idea?


Solution

  • To understand why the paint method is invoked excessively, you can start by checking DefaultTableCellRenderer JavaDoc.
    You also need to understand Swing drawing mechanism and how revalidation works.
    You can read about Painting in AWT and Swing here.

    A simple and efficient (performance-wise & code-wise) rule of thumb, is to extend DefaultTableCellRenderer and customize it to your needs.
    Customization is usually done by overriding setValue() or getTableCellRendererComponent().

    It's important to note that getTableCellRendererComponent():

    1. Usually returns a reference to itself.
    2. Should not create a new object each time it is called exactly for performance reasons.
    3. Acts as a rubber-stamp for rendering all cells, one at a time.
    4. Uses an optimized Object (Modified JLabel in the case of DefaultTableCellRenderer) for drawing, revalidation and repainting.

    Try comparing your existing implementation and this implementation using the profiler to convince yourself that it produces much less drawing and layout events as well as a better CPU utilization.