2

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

Community
  • 1
  • 1
jon.mervine
  • 87
  • 2
  • 10

3 Answers3

4

I've read about overriding prepareRenderer or getTableCellRendererComponent. The conditional rendering logic is then within the Overridden method. 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.

Why do you say this and what data do you have to back up this statement because it is wrong.

prepareRenderer extends JTable

A method cannot extend a class, so this doesn't make sense.

so it's overridden method only has access to that particular instance of JTable and getTableCellRendererComponent is set through the setCellRenderer of a particular column from the columnModel of a particular JTable.

Methods can have access to whatever the programmer lets them have access to. The key is in passing references.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I've added example code, some sources, and rephrased parts. I know prepareRenderer doesn't extend JTable explicitly, but that a class that extends JTable contains the overridden method. Also can you clarify what in the first quote block is wrong and why? Thanks – jon.mervine Sep 20 '12 at 16:21
3

I'd probably use some kind "highlight model" that was capable of determining which rows in which tables should be highlight (and how).

You'd then either provide this directly to the cell renderer or extract it from the table directly in the cell renderer (this however assumes that the table is of the correct type and opens up a whole can of worms).

So essentially you might end up with something like...

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    // Seed the component with the default values
    super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    // You may need to change the value of the component to reflect what
    // you want to display here

    // It should be noted, that this method will override the selection
    // highlighting, you may want to check isSelected and make
    // your own decisions over what needs to be done.
    HighlightModel model = getHighlightModel();
    // You should check for null
    Color color = model.getHighlightBackgroundFor(table, row);
    if (color != null) {
        setOpaque(true);
        setBackground(color);
    }

    return this; // Assuming you've used a component as a base renderer ;)

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Would this be a "HighlightModel", or would this be a TableModel with additional logic to allow for checking highlighting color? Just curious – Panky Sep 19 '12 at 23:28
  • 1
    Well, that's up to you. I'd probably start with an interface that defines the methods that be called against it, then the implementation doesn't matter – MadProgrammer Sep 20 '12 at 00:01
  • That makes sense. Frequently find myself implementing some sort of TableModel so everything JTable related looks like that sort of nail to me lately. – Panky Sep 20 '12 at 00:03
  • 2
    @Panky _would this be a TableModel with additional logic_ definitely not - it's a pure visual decoration which does use the data. Nicely (biased me :-) separated in SwingX: you would put the logic into a HighlightPredicate and configure a Highlighter with that predicate – kleopatra Sep 20 '12 at 09:25
3

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);
kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • Of the other answers I liked this one the most. It took a while but I finally figured out how to get table comparison to work in regards to highlighting. I must say the documentation for JXTable is sparse but it seems to be working well. Thanks – jon.mervine Sep 24 '12 at 21:04