Search code examples
javaswingjtablecomparatorrenderer

Compare two or more JTables and 'Highlight' differences


I am building a swing application that will have a list of items on the left and tables on the right. The number of tables displayed on the right depend on which item was selected on the left. I want to be able to "highlight" (setBackground) of all the rows that are the same in all the tables being displayed.

I've read about overriding prepareRenderer or getTableCellRendererComponent. The conditional rendering logic is then within the Overridden method.

DefaultTableCellRenderer getTableCellRendererComponent never gets called http://tips4java.wordpress.com/2010/01/24/table-row-rendering/ http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#renderer

But from what I can tell and what I understand (Please correct me if I'm wrong) neither option allows you the ability to compare two different JTables at the same time within this overridden method. prepareRenderer is overridden in a class that extends JTable so it is instantiated on a particular table. The overridden method then only effects that particular instance of a Table.

public class CustomRenderer extends JTable {
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
    Component c = super.prepareRenderer(renderer, row, column);
    //  add custom rendering here
    return c;
}};

...
CustomRenderer currTable = new CustomRenderer();

getTableCellRendererComponent is set through the setCellRenderer of a particular column from the columnModel of a particular JTable.

public class CustomRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        if (isSelected) {
            l.setBackground(Color.gray);
        }
        else {
            l.setBackground(Color.white);
        }
    return l;
    }};

...
CustomRenderer cr = new CustomRenderer();
currTable.getcolumnModel().getColumn(1).setCellRenderer(cr);

So then how would I do something like

if(tableOne.getValueAt(1, 1).equals(tableTwo.getValueAt(1, 1) 
//set Cell 1,1 background(Color.blue)
else
//set Cell 1,1 background(Color.red)

Right now I have a really ugly hack that uses Multiple table cell Selections with a getTableCellRendererComponent method that tests the isSelected boolean and changes background accordingly. This is good enough for now (Since I'm the only one using this program) but there has to be a better way to be able to simultaneously compare and change the rendering of one table based on conditions or values of a different table.

Or could I be going about the problem wrong?

Thanks in advance for reading/replying


Solution

  • using SwingX infrastructure, it's as easy as

    • implement a HighlightPredicate which decides whether a not a cell should be highlighted
    • instantiate a Highlighter (f.i. a ColorHighlighter which decorates by setting the background color) and add it to both tables
    • implement/register some listener which sets the predicate to the Highlighter, depending on state

    Below is a short snippet which uses a EqualsHighlightPredicate configured with the selected item in a list to highlight all cells with the same content. Enjoy!

    final JXList list = new JXList(AncientSwingTeam.createNamedColorListModel());
    JXTable table = new JXTable(new AncientSwingTeam());
    final ColorHighlighter highlighter = new ColorHighlighter(
            HighlightPredicate.NEVER, Color.YELLOW, null);
    list.addHighlighter(highlighter);
    table.addHighlighter(highlighter);
    ListSelectionListener l = new ListSelectionListener() {
    
        @Override
        public void valueChanged(ListSelectionEvent e) {
            if (e.getValueIsAdjusting()) return;
            highlighter.setHighlightPredicate(
                    createPredicate(list.getSelectedValue()));
        }
    
        private HighlightPredicate createPredicate(Object selectedValue) {
            if (selectedValue == null) return HighlightPredicate.NEVER;
            return new HighlightPredicate.EqualsHighlightPredicate(selectedValue);
        }
    };
    list.getSelectionModel().addListSelectionListener(l);