3

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();
    }
}
4

2 回答 2

4

You are not able to create tooltip for checkbox inside cell renderer. Actually that component doesn't exists at the moment you are trying to move mouse over it. It is just an image. You need to create tooltip for your JTable

private void tableMouseMoved(java.awt.event.MouseEvent evt) {
    String toolTipText;
    int row = table.rowAtPoint(evt.getPoint());
    int column = table.columnAtPoint(evt.getPoint());

    if (row >= 0) {
        Object o = table.getValueAt(row, column);
        if (column == YourTableModel.COLUMN_INDEX_WITH_CHECKBOX) {
            Boolean value = (Boolean) o;
            if (value == Boolean.TRUE) {
                toolTipText = "Tooltip text for true value";
            } else {
                toolTipText = "Tooltip text for false value";
            }  
        } 
    }
}

And you need to register listener for MouseEvent of course:

javax.swing.JTable table = new JTable();
table.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
    public void mouseMoved(java.awt.event.MouseEvent evt) {
        tableMouseMoved(evt);
    }
});
于 2012-04-25T12:58:23.247 回答
3

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

于 2012-04-25T12:46:21.797 回答