14

Even I read and test answers by @kleopatra

enter image description here

enter image description here

enter image description here

from SSCCE

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

public class SelectedTableHeader {

    private JFrame frame = new JFrame("Table Demo");
    private JTableHeader header;
    private Object selectedColumn = null;
    private String[] columnNames = {"String", "Integer", "Float", "Double", "Locale & Double", "Boolean"};
    private Object[][] data = {
        {"aaa", new Integer(12), new Float(12.15), new Double(100.05), new Double(12.05), true},
        {"bbb", new Integer(5), new Float(7.154), new Double(6.1555), new Double(417.55), false},
        {"CCC", new Integer(92), new Float(0.1135), new Double(3.1455), new Double(11.05), true},
        {"ddd", new Integer(12), new Float(31.15), new Double(10.05), new Double(23.05), true},
        {"eee", new Integer(5), new Float(5.154), new Double(16.1555), new Double(17.55), false},
        {"fff", new Integer(92), new Float(4.1135), new Double(31.1455), new Double(3.05), true}};
    private TableModel model = new DefaultTableModel(data, columnNames) {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };
    private JTable table = new JTable(model);

    public SelectedTableHeader() {
        header = table.getTableHeader();
        header.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                JTableHeader h = (JTableHeader) e.getSource();
                int i = h.columnAtPoint(e.getPoint());
                Object o = h.getColumnModel().getColumn(i).getHeaderValue();
                if (i < 0) {
                    selectedColumn = null;
                    return;
                }
                selectedColumn = o;
                h.requestFocusInWindow();
            }
        });
        final TableCellRenderer hr = table.getTableHeader().getDefaultRenderer();
        header.setDefaultRenderer(new TableCellRenderer() {

            private JLabel lbl;

            @Override
            public Component getTableCellRendererComponent(
                    JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if (selectedColumn == value) {
                    lbl = (JLabel) hr.getTableCellRendererComponent(table, value, true, true, row, column);
                    lbl.setBorder(BorderFactory.createCompoundBorder(lbl.getBorder(), BorderFactory.createLineBorder(Color.red, 1)));
                    lbl.setHorizontalAlignment(SwingConstants.LEFT);
                } else {
                    lbl = (JLabel) hr.getTableCellRendererComponent(table, value, false, false, row, column);
                    lbl.setBorder(BorderFactory.createCompoundBorder(lbl.getBorder(), BorderFactory.createEmptyBorder(0, 5, 0, 0)));
                    lbl.setHorizontalAlignment(SwingConstants.CENTER);
                }
                if (column == 0) {
                    lbl.setForeground(Color.red);
                } else {
                    lbl.setForeground(header.getForeground());
                }
                /*return (value == selectedColumn) ? hr.getTableCellRendererComponent(
                table, value, true, true, row, column) : hr.getTableCellRendererComponent(
                table, value, false, false, row, column);*/
                return lbl;
            }
        });
        table.setRowHeight(20);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scroll = new JScrollPane(table);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(scroll);
        frame.pack();
        frame.setLocation(150, 150);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                SelectedTableHeader selectedTableHeader = new SelectedTableHeader();
            }
        });
    }
}
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • And what is the problem you are having? The SSCCE works fine for me. – Jakub Zaverka Mar 24 '12 at 11:15
  • @Jakub Zaverka maybe there isn't issue with Render, true is I have issues with ArraysXxxException by implements Renderer by (@kleopatra) – mKorbel Mar 24 '12 at 11:18
  • EDIT removed use_less RowSorter – mKorbel Mar 24 '12 at 11:20
  • What do you mean, ArraysXxxException? Like ArrayIndexOutOfBoundsException? – Jakub Zaverka Mar 24 '12 at 11:28
  • @mKorbel: Works for me, too. I think kleopatra's answer refers to an implementation detail in `DefaultTableCellRenderer`; in contrast, your custom implementation of `TableCellRenderer` works around the problem in a different way. – trashgod Mar 24 '12 at 14:13
  • @trashgod agreed, you are right, heavens, without any success, – mKorbel Mar 24 '12 at 16:34
  • @mKorbel: If you extend `DefaultTableCellRenderer` in order to apply kleopatra's approach, could you do something like [`applyUI()`](http://stackoverflow.com/a/7137801/230513) the get the header decorations? – trashgod Mar 24 '12 at 22:06
  • you are getting array out of bounds acception while adding or deleting rows.. I am asking because i have also faced same problem... – Bharat Sharma Aug 16 '12 at 06:26
  • hmm ... what's the problem? And why that funny way of configuring the default header (as your rendering component _is_ the default) – kleopatra Jul 18 '13 at 13:42
  • @kleopatra there are some differencies betweens methods accesible for (J)Component and JLabel, maybe in this time JLabel can't implements something that invoked me ....., – mKorbel Jul 18 '13 at 13:45

2 Answers2

4

In my experience, it's better to get the DefaultTableCellHeaderRenderer when you overwrite any JTable Renderer. So, instead of messing with the JLabel from the Renderer directly, you grab the Renderer with super(). So, your code should look like this:

header.setDefaultRenderer(new DefaultTableCellHeaderRenderer() {


    @Override
    public Component getTableCellRendererComponent(
            JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        DefaultTableCellHeaderRenderer rendererComponent = (DefaultTableCellHeaderRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        if (selectedColumn == value) {
            rendererComponent.setBorder(BorderFactory.createCompoundBorder(rendererComponent.getBorder(), BorderFactory.createLineBorder(Color.red, 1)));
            rendererComponent.setHorizontalAlignment(SwingConstants.LEFT);
        } else {
            rendererComponent.setBorder(BorderFactory.createCompoundBorder(rendererComponent.getBorder(), BorderFactory.createEmptyBorder(0, 5, 0, 0)));
            rendererComponent.setHorizontalAlignment(SwingConstants.CENTER);
        }
        if (column == 0) {
            rendererComponent.setForeground(Color.red);
        } else {
            rendererComponent.setForeground(header.getForeground());
        }

        return rendererComponent;
    }
});

To try and answer your questions directly:

Question 1:

Q: How do I correctly use customer renderers to paint specific cells in a JTable?

A: Your current code is setting a Renderer on the JTableHeader. To add a Renderer on your table cells would be similar code to what's above, only you'd set it through the Column model:

table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        // Set your code to render your component.

        return renderer;
    }

});

Note about this: JTables are column-based, which means that all the data in a certain column must be the same type (your SSCCE follows this convention). My favorite thing to do is to provide a custom Renderer for each type. For example, whenever I have a Date column, I use this renderer:

import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import org.joda.time.LocalDate;

/**
 *
 * @author Ryan
 */
public class DateCellRenderer extends DefaultTableCellRenderer {

    String pattern;
    public DateCellRenderer(String pattern){
        this.pattern = pattern;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        if (value != null && value instanceof LocalDate) {
            renderer.setText(((LocalDate)value).toString(pattern));
        } else
            throw new IllegalArgumentException("Only supported Object type is LocalDate.");

        return renderer;
    }
}

And I call this code with something similar:

table.getColumn("Date Entered").setCellRenderer(new DateCellRenderer("MMM dd, yyyy"));

Question 2:

Q: particular one table header color java swing

A: Umm.. Your SSCCE seems to have it figured out.

Question 3:

Q: about super.getTableCellRendererComponent(...) must be last code line before returns, I'm not able to write correct Renderer by those suggestion, for me works only this way

A: I'm not sure what you mean "must be last code line before returns." That is not the case, proven by the code snip I gave above

Question 4:

Q: JLabel is added for Borders, HorizontalAlignment and Foreground, especially Background caused me a few non_senses by using Component instead of JLabel, (not important here somehow)

A: Ok... the DefaultTableCellHeaderRenderer is sufficient for all of those, borders, alignment, foreground and background.

ryvantage
  • 13,064
  • 15
  • 63
  • 112
0

I had this happen to me in the past and I was convinced it had to do with the Cell Renderer, but the ArraysXxxException kind of Exceptions hunted me because I had forgotten to unselect and stop editing the cell before adding/removing rows. You should try clearSelection() and table.getCellEditor().stopCellEditing(); on your JTable before remove/add and see if that solves your problem.

First, of course, make sure it is editing:

if (table.isEditing()) {
    table.getCellEditor().stopCellEditing();
}
Bigger
  • 1,807
  • 3
  • 18
  • 28