How to Put a Control in the Jtableheader of a Jtable

How can I put a control in the JTableHeader of a JTable?

There are two parts of the problem (as I see it :-)

Usability: inventing UI-interaction/elements is prone to confusing users. In no particular order:

  • the column header title is meant to describe the content of the column, that content description is lost when in replacing it with an action description
  • it's not immediately (for me, the dumbest user on earth :-) clear that the header cell has the function of a toggle button. Accidentally clicking it will loose all earlier content state in that column

So even if interaction analysis comes out with a clear we-do-need/want-it,

  • action only in-addition to the content
  • use a widget that's clearer (e.g. a tri-state checkbox all-de-/selected, mixed content). Also, de-/selecting must both be possible from mixed content. On second thought, a checkbox probably isn't the best choice either, didn't dig further
  • minimize the possibility to accidentally (just for me :-) change bulk state, (e.g. by a clear visual separation of an active area - the checkbox icon) from the "normal header" region.

Technical aspects

  • TableHeader is not designed for "live" components. Whatever is wanted has to be controlled by ourselves
  • examples are around (e.g. JIDE grid supports adding components)
  • fiddling with header tends to look unattractive because it's not trivial to change the renderer and at the same time keep the LAF provided appearance

Can I add a button to a JTable column header?

Here is an example where someone wanted to do the same thing.

Adding JButton to the JTable

Yes, it is possible. You can simply add the button to the table header. The only thing to know is that JTableHeader does not have a layout, so you need to set one.

Here is a simple demo code of this:

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;

public class TestTable2 {

protected void initUI() {
DefaultTableModel model = new DefaultTableModel();
for (int i = 0; i < 5; i++) {
model.addColumn("Col-" + (i + 1));
}
for (int i = 0; i < 200; i++) {
Vector<Object> row = new Vector<Object>();
for (int j = 0; j < 5; j++) {
row.add("New cell - " + (j + 1));
}
model.addRow(row);
}
JTable table = new JTable(model);
final JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(button, "You have clicked me");
}
});
JTableHeader header = table.getTableHeader();
header.setLayout(new FlowLayout(FlowLayout.TRAILING, 5, 0));
header.add(button);
JFrame frame = new JFrame(TestTable2.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollpane = new JScrollPane(table);
frame.add(scrollpane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
new TestTable2().initUI();
}
});
}

}

JTable Right Align Header

Here's an alternate approach to modifying the TableCellRenderer of a table's JTableHeader. It's not strictly necessary for this usage, but it minimizes the impact on the UI delegate's appearance.

Typical usage:

JTable table = new JTable(…);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new HeaderRenderer(table));

Custom header renderer:

private static class HeaderRenderer implements TableCellRenderer {

DefaultTableCellRenderer renderer;

public HeaderRenderer(JTable table) {
renderer = (DefaultTableCellRenderer)
table.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.CENTER);
}

@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int col) {
return renderer.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
}
}


Related Topics



Leave a reply



Submit