Question

I have Checkbox in JTable Header, I am using Nimbus L&F and customize the header background but the background of the checkbox takes the default grey background not the customize one as others column do.

Following is the CheckboxRenderer class

public class CheckBoxHeader extends JCheckBox implements TableCellRenderer{

public CheckBoxHeader(ItemListener itemListener) {      
    addItemListener(itemListener);
    setHorizontalAlignment(SwingConstants.CENTER);
    setOpaque(true);        
}

public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {                    
        JTableHeader header = table.getTableHeader();           
        Color bg = header.getBackground();
        setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));     
    return this;
}

And in Table

TableColumn tc = getColumnModel().getColumn(0);  
tc.setCellEditor(getDefaultEditor(Boolean.class));  
tc.setCellRenderer(getDefaultRenderer(Boolean.class));      
((JComponent)getDefaultRenderer(Boolean.class)).setOpaque(true);        
tc.setHeaderRenderer(new CheckBoxHeader());

AFAIK to get the proper rendering of the header it should render with DefaultTableCellRenderer but i am not getting the way for it. Any suggestions?

Was it helpful?

Solution

I'm not so sure if it work on all LnF(testing only Windows 7, Java 1.7.0_03):

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class NimbusHeaderCheckBox {
  public JComponent makeUI() {
    Object[] columnNames = {Status.INDETERMINATE, "Integer", "String"};
    Object[][] data = {{true, 1, "b"}, {false, 9, "a"}, {true, 5, "c"}};
    DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }
    };
    JTable table = new JTable(model);
    model.addTableModelListener(new HeaderCheckBoxHandler(table));

    TableCellRenderer r = new HeaderRenderer(table.getTableHeader(), 0);
    table.getColumnModel().getColumn(0).setHeaderRenderer(r);
    //<ins>
    TableCellRenderer leftAlign = new LeftAlignHeaderRenderer();
    table.getColumnModel().getColumn(1).setHeaderRenderer(leftAlign);
    table.getColumnModel().getColumn(2).setHeaderRenderer(leftAlign);
    //</ins>
    table.getTableHeader().setReorderingAllowed(false);
    return new JScrollPane(table);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() { createAndShowGUI(); }
    });
  }
  public static void createAndShowGUI() {
    try {
      //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels())
        if ("Nimbus".equals(laf.getName())) UIManager.setLookAndFeel(laf.getClassName());
    } catch(Exception e) {
      e.printStackTrace();
    }
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new NimbusHeaderCheckBox().makeUI());
    frame.setSize(320, 240);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}
class HeaderRenderer extends JCheckBox implements TableCellRenderer {
  public HeaderRenderer(JTableHeader header, final int targetColumnIndex) {
    super((String)null);
    setOpaque(false);
    setFont(header.getFont());
    header.addMouseListener(new MouseAdapter() {
      @Override public void mouseClicked(MouseEvent e) {
        JTableHeader header = (JTableHeader)e.getSource();
        JTable table = header.getTable();
        TableColumnModel columnModel = table.getColumnModel();
        int vci = columnModel.getColumnIndexAtX(e.getX());
        int mci = table.convertColumnIndexToModel(vci);
        if(mci == targetColumnIndex) {
          TableColumn column = columnModel.getColumn(vci);
          Object v = column.getHeaderValue();
          boolean b = Status.DESELECTED.equals(v)?true:false;
          TableModel m = table.getModel();
          for(int i=0; i<m.getRowCount(); i++) m.setValueAt(b, i, mci);
          column.setHeaderValue(b?Status.SELECTED:Status.DESELECTED);
        }
      }
    });
  }
  @Override public Component getTableCellRendererComponent(
      JTable tbl, Object val, boolean isS, boolean hasF, int row, int col) {
    if(val instanceof Status) {
      switch((Status)val) {
      case SELECTED:
        setSelected(true); setEnabled(true); break;
      case DESELECTED:
        setSelected(false); setEnabled(true); break;
      case INDETERMINATE:
        setSelected(true); setEnabled(false); break;
      }
    } else {
      setSelected(true); setEnabled(false);
    }
    TableCellRenderer r = tbl.getTableHeader().getDefaultRenderer();
    JLabel l=(JLabel)r.getTableCellRendererComponent(tbl, null, isS, hasF, row, col);

    l.setIcon(new CheckBoxIcon(this));
    l.setText(null); //XXX Nimbus LnF ???
    ////This block has no effect at all as all the columns are center aligned
    ////(pointed out by rcnpl)
    //if(tbl.convertColumnIndexToModel(col)==0) {
    //  l.setHorizontalAlignment(SwingConstants.CENTER);
    //} else {
    //  l.setHorizontalAlignment(SwingConstants.LEFT);
    //}
    //<ins>
    l.setHorizontalAlignment(SwingConstants.CENTER);
    //</ins>
    return l;
  }
}
//<ins>
class LeftAlignHeaderRenderer implements TableCellRenderer {
  @Override public Component getTableCellRendererComponent(
    JTable t, Object v, boolean isS, boolean hasF, int row, int col) {
    TableCellRenderer r = t.getTableHeader().getDefaultRenderer();
    JLabel l=(JLabel)r.getTableCellRendererComponent(t, v, isS, hasF, row, col);
    l.setHorizontalAlignment(SwingConstants.LEFT);
    return l;
  }
}
//</ins>
enum Status { SELECTED, DESELECTED, INDETERMINATE }
class CheckBoxIcon implements Icon {
  private final JCheckBox check;
  public CheckBoxIcon(JCheckBox check) {
    this.check = check;
  }
  @Override public int getIconWidth() {
    return check.getPreferredSize().width;
  }
  @Override public int getIconHeight() {
    return check.getPreferredSize().height;
  }
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    SwingUtilities.paintComponent(
        g, check, (Container)c, x, y, getIconWidth(), getIconHeight());
  }
}
class HeaderCheckBoxHandler implements TableModelListener {
  private final JTable table;
  public HeaderCheckBoxHandler(JTable table) {
    this.table = table;
  }
  @Override public void tableChanged(TableModelEvent e) {
    if(e.getType()==TableModelEvent.UPDATE && e.getColumn()==0) {
      int mci = 0;
      int vci = table.convertColumnIndexToView(mci);
      TableColumn column = table.getColumnModel().getColumn(vci);
      Object title = column.getHeaderValue();
      if(!Status.INDETERMINATE.equals(title)) {
        column.setHeaderValue(Status.INDETERMINATE);
      } else {
        int selected = 0, deselected = 0;
        TableModel m = table.getModel();
        for(int i=0; i<m.getRowCount(); i++) {
          if(Boolean.TRUE.equals(m.getValueAt(i, mci))) {
            selected++;
          } else {
            deselected++;
          }
        }
        if(selected==0) {
          column.setHeaderValue(Status.DESELECTED);
        } else if(deselected==0) {
          column.setHeaderValue(Status.SELECTED);
        } else {
          return;
        }
      }
      table.getTableHeader().repaint();
    }
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top