0

I have a swing JXTable and the requirement is that background color must change if a field differs from the previous row.

Here is an example :

  • Row 0 : var = 1 -> Background BLUE

  • Row 1 : var = 1 -> Background BLUE

  • Row 2 : var = 2 -> Background RED

  • Row 3 : var = 3 -> Background BLUE

I've tried several solutions.

Overriding prepareRenderer, but this solution is not working fine. The lines blinks and color changes in function of the first line visible in the table.

    @Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
{
    Component c = super.prepareRenderer ( renderer , row , column );
    if(lastRow  != -1)
    {
        Data actualData = ( ( MessagesTableModel ) getModel ( ) ).getData ( row );
        Data previousData = ( ( MessagesTableModel ) getModel ( ) ).getData ( lastRow );
        if ( previousData != null )
        {
            if ( previousData.getNbr ( ) != actualData.getNbr ( ) )
            {
                if(lastColor.equals ( COLOR1 ))
                {
                    System.out.println ("A");
                    lastColor = COLOR2;
                }
                else
                {
                    System.out.println ("b");
                    lastColor = COLOR1;
                }
            }
        }
    }
    lastRow = row;
    c.setBackground ( lastColor );
    return c;
}

I've also think of defining a custom TableCellRender, but it was not concluant.

So I'm stuck I don't know how to do. Do you have any suggestions ?

EDIT

I've tried with HighlightPredicate since I'm using JXTable

        HighlightPredicate predicate = new HighlightPredicate ( )
    {
        public boolean isHighlighted(Component renderer, ComponentAdapter adapter)
        {
            Data actualData = ( ( MessagesTableModel ) getModel ( ) ).getData ( adapter.row );
            if ( adapter.row - 1 >= 0 )
            {
                Data previousData = ( ( MessagesTableModel ) getModel ( ) )
                        .getData ( adapter.row - 1 );
                if ( actualData.getNbr ( ) != previousData.getNbr ( ) )
                {   
                    return true;
                }

            }
            return false;
        }
    };

    addHighlighter ( new ColorHighlighter ( predicate , COLOR1 , null ) );

This time, the color changes if the value change, but if the row right after is not changing, the color changes.

  • Row 0 : var = 1 -> Background BLUE

  • Row 1 : var = 1 -> Background BLUE

  • Row 2 : var = 2 -> Background RED

  • Row 3 : var = 2 -> Background BLUE

This is normal because that's what is coded :) But I'm in front of the same problem, how to know if the previous row was highlighted or not.

EDIT 2

I've found a solution, don't seem very clean but it works.

        HighlightPredicate predicate = new HighlightPredicate ( )
    {
        public boolean isHighlighted(Component renderer, ComponentAdapter adapter)
        {
            Data actualData = ( ( MessagesTableModel ) getModel ( ) ).getData ( adapter.row );
            if ( adapter.row - 1 >= 0 )
            {
                Data previousData = ( ( MessagesTableModel ) getModel ( ) )
                        .getData ( adapter.row - 1 );
                if ( actualData.getMsgNbr ( ) != previousData.getMsgNbr ( ) )
                {   
                    adapter.row--;
                    if(isHighlighted ( renderer , adapter ))
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }                       
                }
                else
                {
                    adapter.row--;
                    if(isHighlighted ( renderer , adapter ))
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return false;
        }
    };

    addHighlighter ( new ColorHighlighter ( predicate , COLOR1 , null ) );

Thank you all for your help !

FlorianB
  • 31
  • 4
  • in SwingX you shouldn't override prepareRenderer (nor implement a custom renderer) - instead implement/use a Highlighter and an appropriate HighlightPredicate for visual decoration. From your description it sounds more like a data property, not mere visuals? If so, let the model decide if a row is different and expose a property which can be used in a HighlightPredicate – kleopatra Jan 07 '13 at 15:25
  • plus: the sequence (of row index) of calling a renderer is undefined - never-ever let it have state related to a "previously" configured row – kleopatra Jan 07 '13 at 15:32
  • [maybe](http://stackoverflow.com/questions/7132400/jtable-row-hightlighter-based-on-value-from-tablecell) – mKorbel Jan 07 '13 at 15:55
  • @mKorbel - exactly, you beat me finding it :-) – kleopatra Jan 07 '13 at 16:04
  • @kleopatra hmmmm ...., both this answers there is about excelent logics, greats minds, not about JTable, great lesson for me (clear logics not about coding) – mKorbel Jan 07 '13 at 16:09
  • you did read the other thread, referenced by @mKorbel, didn't you? If that doesn't help it's time for an SSCCE. – kleopatra Jan 07 '13 at 17:02
  • arrrggg ... don't change the adapter, it's strictly read-only (though it doesn't look it, early api accident ;-)! – kleopatra Jan 08 '13 at 12:29

2 Answers2

2

You also need to make the renderer opaque:

if (c instanceof JComponent)
    ((JComponent)c).setOpaque(true);
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • I have colors, but not as I want, I edited my message to explain more. – FlorianB Jan 07 '13 at 15:16
  • @FlorianB 2 things can cause this: 1) you are making the assumption that all rows are rendered every time 2) before the painting of the table, you don't reset the value of `lastColor`. That last issue can be solved by overriding paintComponent() and before calling super.paintComponent, you reset the value of `lastColor` – Guillaume Polet Jan 07 '13 at 15:27
  • repeating myself: it's _wrong_ to store something like lastColor/lastRow - wherever you do it. There simply is no notion of sequence when painting. – kleopatra Jan 07 '13 at 15:47
  • I know, I realized it by trying this solution and reading more further the documentation. That's why I search another way to do this. – FlorianB Jan 07 '13 at 15:51
2
int lastRow=Math.max(0, row-1);

Instead of saving last row index just use actual row value and subtract 1.

StanislavL
  • 56,971
  • 9
  • 68
  • 98