Overriding createToolTip() in a custom CellRenderer

java, jtable, swing, tooltip

Solution

The reason that the `JTable` does not use your tooltip can be seen in the implementation. The `JTable` will indeed use the component returned by the renderer, but it will ask it for its tooltip text. So only settings a custom tooltip text will work if you stick to the default `JTable` implementation. Just a quick copy-paste of the relevant part of the `JTable` source code to illustrate this:

    if (component instanceof JComponent) {
        // Convert the event to the renderer's coordinate system
        Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
        p.translate(-cellRect.x, -cellRect.y);
        MouseEvent newEvent = new MouseEvent(component, event.getID(),
                                  event.getWhen(), event.getModifiers(),
                                  p.x, p.y,
                                  event.getXOnScreen(),
                                  event.getYOnScreen(),
                                  event.getClickCount(),
                                  event.isPopupTrigger(),
                                  MouseEvent.NOBUTTON);

        tip = ((JComponent)component).getToolTipText(newEvent);
    }

So yes, you will have to override the `JTable` method if you really want an image as tooltip for your check box.

On a side-note: your renderer code has weird behavior. The

final DateFormat df = new SimpleDateFormat("h:mm aa");
table.setValueAt(df.format(value), row, column);

seems incorrect. You should replace the `setValueAt` call by a

JLabel label = new JLabel();//a field in your renderer
//in the getTableCellRendererComponent method
label.setText( df.format( value ) );
return label;

or something similar. The renderer should not adjust the table values, but create an appropriate component to visualize the data. In this case a `JLabel` seems sufficient. And as Stanislav noticed in the comments, you should not constantly create new components. That defeats the purpose of the renderer which was introduced to avoid creating new components for each row/column combination. Note that the method is called `getTableCellRendererComponent` (emphasis on `get`) and not `createTableCellRendererComponent`

Problem

I'm trying to get a custom ToolTip for a specific column of a JTable. I've already created a CellRenderer (of which I've been changing other cell-specific attributes successfully): ``` private class CustomCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JComponent c = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (value != null) { if(column == 1 && value instanceof Date) { final DateFormat df = new SimpleDateFormat("h:mm aa"); table.setValueAt(df.format(value), row, column); } else if(column == 2) { c.setToolTipText((String) value); } else if(column == 4) { final Mail m = main.selectedPage.messages.get(row); JCheckBox checkBox; if((Boolean) value) { checkBox = new JCheckBox() { @Override public JToolTip createToolTip() { System.out.println("Passed"); return new ImageToolTip(m.getImage()); } }; checkBox.setToolTipText(m.attachName); } else checkBox = new JCheckBox(); checkBox.setSelected(((Boolean)value).booleanValue()); c = checkBox; } } else { c.setToolTipText(null); } return c; } } ``` When I override any other JComponent's createTooltip() method like so, it all works fine outside of the Renderer. ``` checkBox = new JCheckBox() { @Override public JToolTip createToolTip() { System.out.println("Passed"); return new ImageToolTip(m.getImage()); } }; ``` From what I can tell, the tooltip is created elsewhere, because "Passed" is never even printed. The `checkBox.setToolTipText(m.attachName);` only results in a default ToolTip with that String. I've found someone with a similar question, but I can't say I completely understand the only resolving answer. Do I need to extend JTable and override `getToolTipText(MouseEvent e)`? If so, I'm not sure what with to get the correct (mine) Tooltip. Please excuse any of my self-taught weirdness. Thanks in advance. :-) EDIT: Thanks to Robin, I was able to piece together something based on JTable's `getToolTipText(MouseEvent e)` code. I'll leave it here for anyone else with a similar problem. Again, I'm not sure it this it the best way to do it, so feel free to critique it below. :-) ``` messageTable = new JTable() { @Override public JToolTip createToolTip() { Point p = getMousePosition(); // Locate the renderer under the event location int hitColumnIndex = columnAtPoint(p); int hitRowIndex = rowAtPoint(p); if ((hitColumnIndex != -1) && (hitRowIndex != -1)) { TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex); Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex); if (component instanceof JCheckBox) { Image img = main.selectedPage.messages.get(hitRowIndex).getImage(); if(((JCheckBox) component).isSelected()) return new ImageToolTip(img); } } return super.createToolTip(); } } ```

Original source