Java - Swing - JTable - Set Color for Selected Row, but not Cell
cell, colors, java, jtable, swing
Solution
The tutorial article Concepts: Editors and Renderers explains that "a single cell renderer is generally used to draw all of the cells that contain the same type of data," as returned by the model's `getColumnClass()` method.
Alternatively, override `prepareRenderer()`, which is invoked for all cells, to selectively alter a row's appearance. This example compares the two approaches, and the article Table Row Rendering expands on the versatility of the approach.
Problem
I am trying to make my table select an entire row when you click on a cell (which can be done by turning off column select), but, I don't want the extra thick border around the specific cell you clicked to be highlighted. I was hoping this would be easy but apparently it involves renderers so I did a lot of research and the closest I can get is this: ``` JTable contactTable = new JTable(tableModel); contactTable.setCellSelectionEnabled(true); contactTable.setColumnSelectionAllowed(false); contactTable.setRowSelectionAllowed(false); contactTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // This renderer extends a component. It is used each time a // cell must be displayed. class MyTableCellRenderer extends JLabel implements TableCellRenderer { // This method is called each time a cell in a column // using this renderer needs to be rendered. public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) { // 'value' is value contained in the cell located at // (rowIndex, vColIndex) if (isSelected) { // cell (and perhaps other cells) are selected } if (hasFocus) { // this cell is the anchor and the table has the focus this.setBackground(Color.blue); this.setForeground(Color.green); } else { this.setForeground(Color.black); } // Configure the component with the specified value setText(value.toString()); // Set tool tip if desired // setToolTipText((String)value); // Since the renderer is a component, return itself return this; } // The following methods override the defaults for performance reasons public void validate() {} public void revalidate() {} protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {} public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {} } int vColIndex = 0; TableColumn col = contactTable.getColumnModel().getColumn(vColIndex); col.setCellRenderer(new MyTableCellRenderer()); ``` I copied the Renderer from an example and only changed the hasFocus() function to use the colors I wanted. Setting colors in `isSelected()` did nothing. The problem with this code is: It only works on one column specified by vColIndex at the bottom. Obviously I want this applied to all columns so clicking on a cell in one highlights the entire row. I could make a for loop to change it to every cell but I figure there's a better way of doing this that changes the cellRenderer for ALL columns at once. `setForegroundColor()` works to change text but `setBackgroundColor()` does nothing to the cells background. I would like it to actually change the background color like the property implies. - Solution for #2: Use `this.setOpaque(true);` before assigning backgroundcolor. When the renderer does work, it only works on a single Cell. How can I get it to color all the Cells in the row? - Solution for #3: I figured it out! Instead of using `hasFocus()`, which only affects the single cell, if you enable row selection (`table.setRowSelectionAllowed(true)`) then you put the color changing in the `if(isSelected)` statement. Then the whole row is considered selected and it colors all the cells in! 3 was the big one but if anyone knows #1 or can explain to me why it was designed such that you can only apply the renderer to one column at a time it would be much appreciated.