1

I've already read a lot about CellRendering in Java and I have also visited other Q&As from this great site. Unfortunately I still haven't found the solution for the following Problem:

I want to render a JTable which displays StatusEvents - this is necessary for monitoring a running System. However, those StatusEvents consist of a timestamp, a text and a color.

My goal is it to enable multiple colored rows. To achieve this, I've already defined a new JTable-subclass (Overloading "getCellRenderer related to the Row which is being painted during the inseration process) and a new TableCellRenderer-Subclass, which applies the Color to the Cell.

the Methods look like the following:

MyCustomJTable:

 @Override
    public TableCellRenderer getCellRenderer(int row, int column) {
        TableCellRenderer result = super.getCellRenderer(row, column);
        if ( row == 0 )
        {
            result = colcr;
        }        
        return result;
        }

colcr is my custom CellRenderer which is coloring a Cell in a specific color which is being set before.

The new Cell Renderer looks like the following:

    public class ColorCellRenderer extends DefaultTableCellRenderer {

    ColorCellRenderer ( )
    {
        this.m_Color = null;
    }

    @Override
    public Component getTableCellRendererComponent ( JTable table , Object value , boolean isSelected , 
            boolean hasFocus, int row, int column)
    {
        Component c = super.getTableCellRendererComponent
(table, value, isSelected, hasFocus, row, column);
        if ( m_Color != null )
        {
            if ( row == 0 && column == 0)
            {
                c.setForeground(m_Color);      
            }
        }
        return c;
    } 

    public void setColor ( Color c )
    {
        this.m_Color = c;
    }

    private Color m_Color;

}

Unfortunately the current solution colors just the first row in the latest configured color, but the previously colored rows lose their color and get formatted by default.

Which possibilities do I have to avoid this behaviour?

sincerely

Markus

Emmanuel Bourg
  • 9,601
  • 3
  • 48
  • 76
Markus
  • 13
  • 4
  • There is a ugly workaround which I don't want to apply if an more elegant solution exists: I COULD insert "invisible" markers at the front of any message and cut them out during the display process. The colors would be set by rules like "if ( message.startswith(pattern) ) color = red; or something... – Markus Aug 02 '11 at 07:54
  • i had a similar question a while back. http://stackoverflow.com/questions/5673430/java-jtable-change-cell-color This may help you. I went a different route, so i never implemented this though. – Matt Aug 02 '11 at 08:03

2 Answers2

1

You have to retain the state necessary for the renderer to apply the expected color at a specified location at any time. Swing will not remember the color for you.

You probably want to derive the color from the StatusEvents displayed in your table. In this case you must read the status in the renderer and apply the corresponding color.

Emmanuel Bourg
  • 9,601
  • 3
  • 48
  • 76
1

for example by using prepareRenderer()

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

public class TablePrepareRenderer extends JFrame {

    private static final long serialVersionUID = 1L;
    private JTable table;

    public TablePrepareRenderer() {
        Object[] columnNames = {"Type", "Company", "Shares", "Price"};
        Object[][] data = {
            {"Buy", "IBM", new Integer(1000), new Double(80.50)},
            {"Sell", "MicroSoft", new Integer(2000), new Double(6.25)},
            {"Sell", "Apple", new Integer(3000), new Double(7.35)},
            {"Buy", "Nortel", new Integer(4000), new Double(20.00)}
        };
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }

            @Override
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                Component c = super.prepareRenderer(renderer, row, column);
                int firstRow = 0;
                int lastRow = table.getRowCount() - 1;
                if (row == lastRow) {
                    ((JComponent) c).setBackground(Color.red);
                } else if (row == firstRow) {
                    ((JComponent) c).setBackground(Color.blue);
                } else {
                    ((JComponent) c).setBackground(table.getBackground());
                }
                /*if (!isRowSelected(row)) {
                String type = (String) getModel().getValueAt(row, 0);
                c.setBackground("Buy".equals(type) ? Color.GREEN : Color.YELLOW);
                }
                if (isRowSelected(row) && isColumnSelected(column)) {
                ((JComponent) c).setBorder(new LineBorder(Color.red));
                }*/
                return c;
            }
        };
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        getContentPane().add(scrollPane);
    }

    public static void main(String[] args) {
        TablePrepareRenderer frame = new TablePrepareRenderer();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • thanks, it seems to be a similar principle like Emmanuel posted before. I'll try everything out and let you know the results. Thanks guys! – Markus Aug 02 '11 at 08:46
  • Not exactly; `prepareRenderer()` sees _all_ renderer requests; it's a good choice for affecting entire rows or single cells. In contrast, `setDefaultRenderer()` applies to a specific type in each column that reports that type in the model's `getColumnClass()` method. See [Using Custom Renderers](http://download.oracle.com/javase/tutorial/uiswing/components/table.html#renderer). – trashgod Aug 02 '11 at 13:55
  • @trashgod yes in case that `JTable` is static, but for dynamical contents is for me better an confortable using `prepareRender`, as `public Component getTableCellRendererComponent(...` – mKorbel Aug 02 '11 at 14:14
  • You're right; `prepareRenderer()` is the better approach, as it affects all renderes. I don't see the need for @Markus' `ColorCellRenderer` at all. – trashgod Aug 02 '11 at 14:21
  • @trashgod hmmm, then s/he must call that programatically after all changes and events in the TableModel and JTable :-) – mKorbel Aug 02 '11 at 14:25