13

I would like to make an editable table and then check the data to make sure its valid. Im not sure how to change the color of just one cell. I would like to get a cell, for example (0,0) and color the foreground to red. I have read the other posts on SO as well as Oracle about the custom ColorRenderer, but i just don't get how i would use this.

Thanks.

kleopatra
  • 51,061
  • 28
  • 99
  • 211
Matt
  • 7,049
  • 7
  • 50
  • 77

7 Answers7

19

Say that the cell you would like to render with a different color represents a status (I'll take Rejected and Approved as examples). I'd then implement a method in my table model called getStatus(int row) which returns the status for any given row.

Then, when that is in place, I'd go about creating a cell renderer responsible for rendering the column which the cell belongs to. The cell renderer would be something in the lines of the below code.

public class StatusColumnCellRenderer extends DefaultTableCellRenderer {
  @Override
  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {

    //Cells are by default rendered as a JLabel.
    JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);

    //Get the status for the current row.
    CustomTableModel tableModel = (CustomTableModel) table.getModel();
    if (tableModel.getStatus(row) == CustomTableModel.APPROVED) {
      l.setBackground(Color.GREEN);
    } else {
      l.setBackground(Color.RED);
    }

  //Return the JLabel which renders the cell.
  return l;

}

Then, when the renderer is in place, simply "apply" the renderer to the table with the following piece of code:

Table.getColumnModel().getColumn(columnIndex).setCellRenderer(new StatusColumnCellRenderer());

With regard to making a cell editable, simply implement the isCellEditable(int rowIndex, int columnIndex) method in your table model. You also need to implement the method setValueAt(Object value, int rowIndex, int columnIndex) if you would like to keep the value which the user provides (which i assume you do!).

sbrattla
  • 5,274
  • 3
  • 39
  • 63
  • Alternatively : You can also avoid implementing the getStatus() method in your table model if you prefer that. Say, if your table model's getValueAt(int rowIndex, int columnIndex) returns the statuses as strings ("APPROVED", "REJECTED") then you could simply have the rendered to check the provided value [...]RendererComponent(table, value, boolean[...]) and change the cell's color based on that. Then you would not need to take the "detour" to the table model to get the status for the current row/column. This might actually be the easiest way to do it... – sbrattla Apr 15 '11 at 07:29
  • 1
    A last little note: if you would go for the solution where you implement getStatus(int row), then make sure to convert the row index using table.convertRowIndexToModel(int row). The row provided to getTableCellRendererComponent() is the view index, which may be different from the model index if the ordering of rows are changed due to sorting. – sbrattla Apr 16 '11 at 11:52
2

I believe the correct way to do colouring in a table is via a ColorHighlighter. The table renderers have problems to render different colours in the same column.

Here is an example of how to use highlighters. In this case it is for highlighting a cell that is not editable.

public class IsCellEditablePredicate implements HighlightPredicate {

   private JXTable table;

   public IsCellEditablePredicate (final JXTable table) {
       this.table = table;
   }

   @Override
   public boolean isHighlighted(Component component, ComponentAdapter componentAdapter) {

        return !table.isCellEditable(componentAdapter.row,
          componentAdapter.column);
   }
}

and then in your code for setuping the table you add the highlighter and its colour parameters:

 ColorHighlighter grayHighlighter = new ColorHighlighter(new IsCellEditablePredicate(table));

    grayHighlighter.setBackground(Color.LIGHT_GRAY);
    grayHighlighter.setForeground(table.getForeground());
    grayHighlighter.setSelectedBackground(table.getSelectionBackground().darker());
    grayHighlighter.setSelectedForeground(table.getSelectionForeground().darker());

    table.setHighlighters(grayHighlighter);
StealthRT
  • 10,108
  • 40
  • 183
  • 342
Mateva
  • 786
  • 1
  • 8
  • 27
2

I would like to make an editable table and then check the data to make sure its valid.

Another approach would be to edit the data before it is saved to the table model to prevent invalid data from being entered.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;

public class TableEdit extends JFrame
{
    TableEdit()
    {
        JTable table = new JTable(5,5);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());

        JScrollPane scrollpane = new JScrollPane(table);
        getContentPane().add(scrollpane);

        //  Use a custom editor

        TableCellEditor fce = new FiveCharacterEditor();
        table.setDefaultEditor(Object.class, fce);
    }

    class FiveCharacterEditor extends DefaultCellEditor
    {
        FiveCharacterEditor()
        {
            super( new JTextField() );
        }

        public boolean stopCellEditing()
        {
            try
            {
                String editingValue = (String)getCellEditorValue();

                if(editingValue.length() != 5)
                {
                    JTextField textField = (JTextField)getComponent();
                    textField.setBorder(new LineBorder(Color.red));
                    textField.selectAll();
                    textField.requestFocusInWindow();

                    JOptionPane.showMessageDialog(
                        null,
                        "Please enter string with 5 letters.",
                        "Alert!",JOptionPane.ERROR_MESSAGE);
                    return false;
                }
            }
            catch(ClassCastException exception)
            {
                return false;
            }

            return super.stopCellEditing();
        }

        public Component getTableCellEditorComponent(
            JTable table, Object value, boolean isSelected, int row, int column)
        {
            Component c = super.getTableCellEditorComponent(
                table, value, isSelected, row, column);
            ((JComponent)c).setBorder(new LineBorder(Color.black));

            return c;
        }

    }

    public static void main(String [] args)
    {
        JFrame frame = new TableEdit();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • This is probably what i am looking for, i will give a shot and let you know. I do have a save button to check that all data is valid before saving. I want to be able to save the data that is valid and skip over data that's not. Thanks! – Matt Apr 15 '11 at 17:12
1

This is the simplest way to color a particular Column or cell in a jTable.

First just create a simple class of CustomRenderer

class CustomRenderer extends DefaultTableCellRenderer <br />
{
    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);
        setForeground(Color.blue); >
        return c;
    }
}

This code gets the column of cell to render

TableColumn col = tblExamHistoryAll.getColumnModel().getColumn(5);
DefaultTableModel model3 = (DefaultTableModel)tblExamHistoryAll.getModel();
col.setCellRenderer(new CustomRenderer());

This is to clear all previous rows from your table. If you do not want them just remove these lines

model3.getDataVector().removeAllElements();
model3.fireTableDataChanged();
caesay
  • 16,932
  • 15
  • 95
  • 160
  • -1 for fireXX from the outside (wondering whether it was you who with the exact [same incorrect answer](http://stackoverflow.com/a/13536681/203657) - same name, new account?) – kleopatra Nov 25 '12 at 11:45
1
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
        int row, int col) {
    Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
    int control = row;
    control = control % 2;
    control = (control == 0) ? 1 : 0;
    if (control == 1) {
        c.setBackground(Color.green);
    } else {
        c.setBackground(Color.cyan);
    }
    return c;
}
  • Welcome to Stack Overflow! Please don't just throw your source code here. Be nice and try to give a nice description to your answer, so that others will like it and upvote it. See: [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – sɐunıɔןɐqɐp Jun 14 '18 at 06:31
0

The most straightforward way is to write a simple TableCellRenderer by extending the DefaultTableCellRenderer and overwriting the getTableCellRendererComponent method to setBackground( Color.RED ). For example:

final JTable table = new JTable(...);
table.setCellRenderer( new DefaultTableCellRenderer() {
    public Component getTableCellRenderer(JTable table, Object value, ...) {
        super.getTableCellRenderer(...);

        if ( value should be highlighted ) {
            setBackground( Color.RED );
        }
        return this;
    }
});
Nate W.
  • 9,141
  • 6
  • 43
  • 65
  • 2
    no - that's incomplete: DefaultTableCellEditor is a broken implementation which exhibits the infamous "Color memory" - when touching colors once, you'll have to do it always, that is add an else branch to if – kleopatra Apr 30 '11 at 13:51
  • @kleopatra You're right, there should be an `else` that resets the color to black. Furthermore, there's no `setCellRenderer` method on `JTable` so this is an incomplete example. My intentions were that it would show the OP enough to get started down the right path and they could learn the little details themselves. – Nate W. May 02 '11 at 17:16
0

You can extend DefaultTableCellRenderer, override getTableCellRendererComponent and call something like

if (myConditions) setBackground(myColor);

before returning "this" when conditions apply but it has a very annoying side-effect of changing the default back-color due to the way DefaultTableCellRenderer.setBackGround is coded.

The trick I found was to entirely duplicate the code of DefaultTableCellRenderer in a class named HackedDefaultTableCellRenderer, add a method that calls directly the Component's setBackground implementation:

public void setComponentBackground(Color c) {
    super.setBackground(c);
}

then derive my customized rendered from this hacked class instead of from DefaultTableCellRenderer, and finally call setComponentBackground instead of setBackground in my customized getTableCellRendererComponent.

The drawback is that this HackedDefaultTableCellRenderer relies on a snapshot of DefaultTableCellRenderer.