Java Tips Weblog

  • Blog Stats

    • 2,571,319 hits
  • Categories

  • Archives

Table Row Rendering

Posted by Rob Camick on January 24, 2010

There are times when you might want to do some custom rendering for an entire row of a table. Based on answers I see in the forums, for most people the first thought is to create a custom renderer. This can be a simple solution in some cases, but are there other alternatives to consider as well?

A renderer is used by a JTable to render a class of data for a given column. So when all the data in the table is of the same class, String for example, then the easiest solution is probably to create a custom String renderer containing your custom row rendering logic.

However, what happens when your table contains multiple classes of data, maybe String, Date, Integer and Boolean? Would you create 4 custom renderers or is there a better way?

In this situation it is possible to write the custom rendering code only once and have it applied to all renderers. The trick is to override the prepareRenderer(…) method of JTable. This method is invoked every time a cell is rendered so it is the perfect place to add row level rendering logic that can be applied to all renderers.

A simple example for overriding this method would be as follows:

JTable table = new JTable(...)
{
    public Component prepareRenderer(
        TableCellRenderer renderer, int row, int column)
    {
        Component c = super.prepareRenderer(renderer, row, column);

        //  Alternate row color 

        if (!isRowSelected(row))
            c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY);

        return c;
    }
};

 You can use this technique to alternate the background color of each row:

… add a row level Border:

… change the background color based on data in the row:

Although this tip was suggested to be used for row rendering. It can be considered any time you want to add common logic to multiple different renderers.

Get The Code

TableRowRenderingTip.java

Related Reading

Java Tutorials: Concepts – Editor and Renderers

20 Responses to “Table Row Rendering”

  1. tbee said

    I’m using this beauty of a hook-in method for all kinds of goodies, like for example:
    – highlight a cell when the value has an error or warning (by wrapping it in a JPanel with a red / orange border)
    – automatically adjust the height of a row if the renderer requires additional room

    This saves the trouble of implementing logic in each and every cell render implementation.

  2. Kleopatra said

    Rob,

    exactly what SwingX does – formalized into “Highlighter” which are pluggable by table (and list, tree) or by column :-)

    The one problem with this approach is that the renderer must play strictly by the rules, that is reset all visual properties in each call to getXXCellRenderingComponent. Most default renderers are misbehaving in one way or another, particularly unfortunate is DefaultTableCellRenderer which doesn’t do so with its colors.

    @Tom, careful: size changing in the prepare can lead to changing the state of the table during the a paint cycle which is a Bad-Thing

    Cheers
    Jeanette

    • Rob Camick said

      As usual, good point about resetting the renderer state. At least my examples take that into account, at least I have not noticed any problems.

      Once I get back from vacation I will update the posting to specifically mention this potential problem.

    • Denis Lemberger said

      Setting the background color using this technique doesn’t work when the renderer is a subclasses of DefaultTreeCellRenderer. It’s background simply remains white.

      Actually setting the background color of a DefaultTreeCellRenderer doesn’t work at all (not even when overriding getTreeCellRendererComponent())!

      Any hints?

      Many thanx in advance
      :-Denis

      • Rob Camick said

        Sorry, I”m not familiar with the details of the Tree renderer. You can try looking at the source code for the default Tree and Table renderers to see why they work differently.

  3. tbee said

    That is exactly why I used the JPanel for my error / warning border; nicely under my own control. Even tried doing the alternating background using that, but the renderer has to be transparent then, and that usually is not the case.

    @Jeanette: no problems so far, but as soon as I run into one I’ll “invokeLater” the call

    I just saw that I use the same hook to make the component look disabled if the cell is not editable.

  4. SongLi said

    Thanks for this solution. However, when I added row sorter, the table color will not change after row sorting. Any suggestion about this problem?

    • Rob Camick said

      When using a table you need to understand the difference between working with the “model” or the “view” when accessing the data. The example code for the “Data” tab has been updated to include sorting on the table and all indexes are converted to model values in the prepare renderer code.

  5. Bob said

    Sorry about this silly question, but following your example, my prepareRederer isn’t being called, so my rows aren’t rendered. Could you help me? What am I doing wrong?

  6. sam said

    Thanks so much for this tutorial. I’m a C++ coder moving to Java and this really helped me a lot.

    Have an eBeer on me!

    Sam

  7. a said

    Thank you so much dude! I kept having the problem that my jtable only set the back ground of two rows using a custom default renderer – both of them strings and couldn’t figure out what that was! In addition if I select a row then the background and font color is also white – so I can’t see the text!!!!! This has solved both problems!!!

  8. I made of this today :) And found the difference between custom renderer and prepareRenderer() :) Thanks again Rob Camick…

  9. rishu said

    If I have a row sorter enable for each column , then this does not help. I mean if u sort rows by double clicking on a column header, the color changes are sticky to cells and do not get reflected on the correct data.

    • Rob Camick said

      If you are getting data from the model then you will need to use:

      int modelRow = convertRowIndexToModel( row );
      

      and then access the model data using the modelRow variable.

  10. Anonymous said

    Hi,

    I’ve used your tip for painting odd rows, but it happens that the selection color is not shown in those rows. Any idea why would it be?

    Thanks

  11. Robert Schmidt said

    Hi Rob!

    After two days searching the web, I found your code. You saved my day! Everything else I tried didn’t work using NetBeans, this does.
    Great work.

    Thanks

  12. Chakib said

    Thanks a lot ;)
    it’s a good job

Leave a comment