Thursday, June 20, 2013

How to change background color of a row relate to a column data

In this post, I explain how to change background color according to data of a column.

First, this is my goal.

The first row, second column is "male", and the background color of the row is light gray.

 
As I change the male to female, the background color is changed to Orange. 

 
 
I will explain this in source code.


package jtbl_color;

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

/**
 *
 * @author Lee
 */
public class ColoredTable extends JPanel{
    
    private JTable table;
    private JScrollPane scrollPane;
    private MyTableModel model;
    private int sexColumn = 1;
    
    // data for the table
    private Object[][] data = {
        {"Singed", "male", false}, 
        {"Akali", "female", false},    
        {"Tristina", "female", true},    
        {"Udyr", "male", false},     
        {"Janna", "female", true}
    };
    
    // column names for the table
    private final String[] columnNames = {
        "Name", "Sex", "Vegetarian"
    };
    
    public ColoredTable() {
        super(new BorderLayout());
        initComponents();
    }
    
    public void initComponents() {
        // Initiate the Abstract Table Model
        model = new MyTableModel();
        
        // Add TableModelListener to the model
        model.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                // get the event, and check if the changed event is data update
                if(e.getType() == TableModelEvent.UPDATE) {
                    // repaint the row
                    rowRepaint(table, table.convertRowIndexToView(e.getFirstRow()));
                }
            }
        });
        // Add the model to the JTable
        table = makeTable(model);
        
        // set the Combo box to sex column
        setSexColumn(table.getColumnModel().getColumn(sexColumn));
        
        // Add the table to the JScrollPane
        scrollPane = new JScrollPane(table);
        
        // Add the scrollPane to the JPanel
        this.add(scrollPane);
    }
    
    // set combo box for sex column
    public static void setSexColumn(TableColumn sexColumn){
        // new combo box
        JComboBox comboBox = new JComboBox();
        // add male and female items to the combo box
        comboBox.addItem("male");
        comboBox.addItem("female");
        // set combo box to the sex column
        sexColumn.setCellEditor(new DefaultCellEditor(comboBox));
    }
    
    // repaint the selected row 
    private static void rowRepaint(JTable table, int row) {
        Rectangle r = table.getCellRect(row, 0, true);
        r.width = table.getWidth();
        table.repaint(r);
    }
    
    // make table for changing colors
    private JTable makeTable(final MyTableModel model) {
        return new JTable(model) {
            @Override
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                Component c = super.prepareRenderer(renderer, row, column);
                String sex = (String)model.getValueAt(
                        convertRowIndexToModel(row), sexColumn);
                
                if(sex.equals("female")) {
                        c.setBackground(Color.ORANGE);
                    } else if (sex.equals("male")) {
                        c.setBackground(Color.LIGHT_GRAY);
                    }
                return c;
            }
        };
    }
    
    // Define the model for the table using AbstractTableModel
    class MyTableModel extends AbstractTableModel {
        // Decide the row count according to the data length   
        @Override       
        public int getRowCount() {        
            return data.length;     
        }     
        
        // decide the column count according to the columnNames length   
        @Override     
        public int getColumnCount() {      
            return columnNames.length;     
        }        
        
        // put the data values into the table.     
        @Override       
        public Object getValueAt(int rowIndex, int columnIndex) {     
            return data[rowIndex][columnIndex];    
        }               
        
        // put the columnNames values into the table column names    
        @Override      
        public String getColumnName(int col){      
            return columnNames[col];     
        }              
        
        // set if the cells in the table are editable.     
        // In this example, all the cells are editable  
        @Override      
        public boolean isCellEditable(int row, int col) {     
            return true;       
        }                
        
        // this is for data change.      
        @Override      
        public void setValueAt(Object value, int row, int col) {      
            data[row][col] = value;      
            fireTableCellUpdated(row, col);   
        }    
        /*     
         * JTable uses this method to determine the default renderer/    
         * editor for each cell.  If we didn't implement this method,       
         * then the last column would contain text ("true"/"false"),     
         * rather than a check box.  (From oracle JTable tutorial)   
         */        
        @Override
        public Class getColumnClass(int c) {        
            return getValueAt(0, c).getClass();     
        }
    }
    
    /**       
     * Create the GUI and show it.   
     * For thread safety,      
     * this method should be invoked from the    
     * event-dispatching thread.       
     * (from Oracle table tutorial)    
     */  
    private static void createAndShowGUI() {     
        //Create and set up the window.       
        JFrame frame = new JFrame("TableRenderDemo");      
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     
        //Create and set up the content pane.      
        ColoredTable newContentPane = new ColoredTable();        
        newContentPane.setOpaque(true); //content panes must be opaque     
        frame.setContentPane(newContentPane);                     
        //Display the window.      
        frame.pack();      
        frame.setVisible(true);       
    }        
    public static void main(String[] args) {     
        //Schedule a job for the event-dispatching thread:   
        //creating and showing this application's GUI.      
        SwingUtilities.invokeLater(new Runnable() {        
            @Override        
            public void run() {   
                createAndShowGUI();   
            }    
        });   
    }
}

I don't remember where I saw this method, so I cannot give you the reference page.
Also, I'm not quite sure what the prepareRenderer does..
More study is required here

No comments:

Post a Comment