Use a custom TableCellRenderer:
// column 1
col = table.getColumnModel().getColumn(1);
col.setHeaderRenderer(new EditableHeaderRenderer( new JButton("Button")));
// column 2
col = table.getColumnModel().getColumn(2);
col.setHeaderRenderer(new EditableHeaderRenderer( new JToggleButton("Toggle")));
// column 3
col = table.getColumnModel().getColumn(3);
col.setHeaderRenderer(new EditableHeaderRenderer( new JCheckBox("CheckBox")));
class EditableHeaderRenderer implements TableCellRenderer {
private JTable table = null;
private MouseEventReposter reporter = null;
private JComponent editor;
EditableHeaderRenderer(JComponent editor) {
this.editor = editor;
this.editor.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
if (table != null && this.table != table) {
this.table = table;
final JTableHeader header = table.getTableHeader();
if (header != null) {
this.editor.setForeground(header.getForeground());
this.editor.setBackground(header.getBackground());
this.editor.setFont(header.getFont());
reporter = new MouseEventReposter(header, col, this.editor);
header.addMouseListener(reporter);
}
}
if (reporter != null) reporter.setColumn(col);
return this.editor;
}
static public class MouseEventReposter extends MouseAdapter {
private Component dispatchComponent;
private JTableHeader header;
private int column = -1;
private Component editor;
public MouseEventReposter(JTableHeader header, int column, Component editor) {
this.header = header;
this.column = column;
this.editor = editor;
}
public void setColumn(int column) {
this.column = column;
}
private void setDispatchComponent(MouseEvent e) {
int col = header.getTable().columnAtPoint(e.getPoint());
if (col != column || col == -1) return;
Point p = e.getPoint();
Point p2 = SwingUtilities.convertPoint(header, p, editor);
dispatchComponent = SwingUtilities.getDeepestComponentAt(editor, p2.x, p2.y);
}
private boolean repostEvent(MouseEvent e) {
if (dispatchComponent == null) {
return false;
}
MouseEvent e2 = SwingUtilities.convertMouseEvent(header, e, dispatchComponent);
dispatchComponent.dispatchEvent(e2);
return true;
}
@Override
public void mousePressed(MouseEvent e) {
if (header.getResizingColumn() == null) {
Point p = e.getPoint();
int col = header.getTable().columnAtPoint(p);
if (col != column || col == -1) return;
int index = header.getColumnModel().getColumnIndexAtX(p.x);
if (index == -1) return;
editor.setBounds(header.getHeaderRect(index));
header.add(editor);
editor.validate();
setDispatchComponent(e);
repostEvent(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
repostEvent(e);
dispatchComponent = null;
header.remove(editor);
}
}
}
Please note that components with popupmenu (e.g. JComboBox or JMenu) don't work well. See: JComboBox fails to expand in JTable TableHeader).
But you can use a MenuButton in the TableHeader:
class MenuButtonTableHeaderRenderer extends JPanel implements TableCellRenderer {
private int column = -1;
private JTable table = null;
private MenuButton b;
MenuButtonTableHeaderRenderer(String name, JPopupMenu menu) {
super(new BorderLayout());
b = new MenuButton(ResourceManager.ARROW_BOTTOM, menu);
b.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
JLabel l = new JLabel(name);
l.setFont(l.getFont().deriveFont(Font.PLAIN));
l.setBorder(BorderFactory.createEmptyBorder(1,5,1,1));
add(b, BorderLayout.WEST);
add(l, BorderLayout.CENTER);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
if (table != null && this.table != table) {
this.table = table;
final JTableHeader header = table.getTableHeader();
if (header != null) {
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
header.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int col = header.getTable().columnAtPoint(e.getPoint());
if (col != column || col == -1) return;
int index = header.getColumnModel().getColumnIndexAtX(e.getPoint().x);
if (index == -1) return;
setBounds(header.getHeaderRect(index));
header.add(MenuButtonTableHeaderRenderer.this);
validate();
b.doClick();
header.remove(MenuButtonTableHeaderRenderer.this);
header.repaint();
}
});
}
}
column = col;
return this;
}
}