I am experimenting the possibility to replace the JTable header cell (JLabel) with a JPanel. The reasoning is to have a more flexible container to place other header related stuff, i.e., multicolumn sorting indicators. Putting a panel is straight-forward however maintaining the LAF seems like the hassle.
My attempt was to override the header renderer and pack the content in a JPanel. It works but the default LAF is gone as expected.
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class JTableHeaderExperimental {
static class XTableHeaderCellRenderer extends DefaultTableCellRenderer{
private TableCellRenderer defaultRenderer;
public XTableHeaderCellRenderer(TableCellRenderer defaultRenderer) {
this.defaultRenderer = defaultRenderer;
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// For the simplicity, skipping sorting icon related stuff
GridBagConstraints constraints = new GridBagConstraints();
JPanel panel = new JPanel(new GridBagLayout());
JLabel extraLabel = new JLabel("Extra label");
JLabel originalLabel = (JLabel) defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 0;
panel.add(extraLabel, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
panel.add(this, constraints);
System.out.println("Original Header Border: " + originalLabel.getBorder().getClass());
System.out.println("New Header Border: " + this.getBorder().getClass());
System.out.println("Header Panel Border: " + panel.getBorder().getClass());
return panel;
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
Object[][] data = {
{"Test", "Data"},
{"Comes", "Here"}
};
String[] columnNames = {"Header 1", "Header 2"};
JFrame frame = new JFrame();
JTable table = new JTable();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table.setModel(model);
table.getTableHeader().setDefaultRenderer(new XTableHeaderCellRenderer(table.getTableHeader().getDefaultRenderer()));
frame.setSize(200, 200);
frame.add(new JScrollPane(table));
frame.setVisible(true);
}
}
Running this code gives the output:
Original Header Border: class javax.swing.plaf.synth.SynthBorder
New Header Border: class javax.swing.border.EmptyBorder
Header Panel Border: class javax.swing.plaf.synth.SynthBorder
and renders:
as opposed to the default system LAF:
I was wondering if it is possible to create a panel and pass the LAF details (i.e., border, bg/fg colors) of the original label.