I am trying to create a table with custom column headers. I want the column headings to include a button that users can click on. The function of the button will be to remove the column from the table. Essentially, I'm trying to create something like this .
Here is my code:
public class CustomColumnHeadersTable { private static String[] columnNames = { "Column 1", "Column 2", "Column 3" }; private static String[][] data = { {"A", "B", "C"}, {"D", "E", "F"}, {"G", "H", "I"} }; public CustomColumnHeadersTable() { DefaultTableModel model = new DefaultTableModel((Object[][]) data, columnNames); JTable table = new JTable(model); JScrollPane scrollPane = new JScrollPane(table);
By default, if I understand correctly, JTable uses JLabel to display column headers. My idea is to use a custom implementation of TableCellRenderer and create my own column header from several components, namely JPanel, which contains JLabel and JButton. I create and return this to the getTableCellRendererComponent (...) function.
Visually it works. The problem is that I cannot detect mouse clicks on the button (or, for that matter, on the panel that holds it). Just adding a MouseListener to a button does not work. The event never came.
I found several similar things on the Internet, but they do not achieve the functionality I need.
First, there is an example of how to put a JCheckBox in the header, here:
http:
The problem is that the whole title is a checkbox. When you click on the checkbox or on the corresponding label, the same effect is created. Therefore, sorting a column is not possible. I would like to have a click on the label to sort the column, and clicking on the close button will remove the column from the table. In other words, the header should have two separate areas with separate mouse event handlers.
I found another example here:
http://www.devx.com/getHelpOn/10MinuteSolution/20425/1954?pf=true
This includes placing JButtons in the cells of the table, and then detecting mouse clicks in the table itself, calculating the column and row where the click occurred, and sending the event to the corresponding button.
There are several issues with this. First, the buttons are in the cells, not in the headers. Secondly, this is again one component, and not several components inside JPanel. Although I got the idea of โโdispatching events from this example, I cannot get it to work for a composite component.
I tried a different approach. I suggested that if I can get the coordinates of the close buttons, then, knowing the coordinates of the mouse click, I can figure out which button to click and send the event accordingly. I conducted several tests and found that the components inside the table header are not actually located on the screen.
I added the JButton static variable to my main (public) class and created a class that implements TableCellRenderer as an inner class of the main class. In getTableCellRendererComponent (...), before returning, I assign the JButton that I just created for this static variable. That way, I can talk to him, so to speak. Then, basically, I tried to use getX (), getY (), getWidth (), getHeight () and getLocationOnScreen () using this static variable. X, Y, Width and Height all return 0. GetLocationOnScreen () crashes the program, saying that the component must be present on the screen for this function to work.
The code for this looks something like this:
public class CustomColumnHeadersTable { private static JButton static_button;
"the CustomColumnCellRenderer class implements the TableCellRenderer" becomes the inner class of the CustomColumnHeadersTable. To do this, I have to discard the static variables in CustomColumnCellRenderer, so I was not worried about icons or URLs or anything like that. Instead of a button with an icon, I just used a simple button that said "BUTTON" ...
Next, inside getTableCellRendererComponent (...), immediately before the return statement, I did
static_button = button;
And finally, inside main (), I tried to do this:
System.out.println("X: " + static_button.getX()); System.out.println("Y: " + static_button.getY()); System.out.println("W: " + static_button.getWidth()); System.out.println("H: " + static_button.getHeight()); System.out.println("LOC: " + static_button.getLocation()); System.out.println("LOC on screen: " + static_button.getLocationOnScreen());
The result is as follows:
X: 0 Y: 0 W: 0 H: 0 LOC: java.awt.Point[x=0,y=0] Exception in thread "main" java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:1943) at java.awt.Component.getLocationOnScreen(Component.java:1917) ...
In other words, the button has all sizes 0, and according to Java, it is actually not on the screen (although I see it ...). Calling the getLocationOnScreen () function causes the program to crash.
So please help if you can. Maybe someone knows how to do this. Maybe you could suggest a different approach to try. Or maybe you know that this is not possible at all ...
Thank you for your help.