Question

I have a custom TableCellRenderer for which I want to display a different tooltip depending on where in the cell the mouse is positioned. The issue I'm running into is that getWidth() is always returning 0 when called from getToolTipText.

Here's an SSCCE:

import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.MouseEvent;

public class Sandbox {
  public static void main(String[] args) {
    JFrame testFrame = new JFrame("Test");
    testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    testFrame.setLayout(new BorderLayout());

    JTable testTable = new JTable(new Object[][]{{"Value 1", null}}, new Object[] {"Column 1", "Column 2"});
    testTable.getColumnModel().getColumn(1).setCellRenderer(new CustomCellRenderer());

    testFrame.add(new JScrollPane(testTable), BorderLayout.CENTER);
    testFrame.pack();
    testFrame.setLocationRelativeTo(null);
    testFrame.setVisible(true);
  }

  private static class CustomCellRenderer implements TableCellRenderer {
    private final JLabel renderer = new JLabel()
    {
      @Override
      protected void paintComponent(Graphics g) {
        g.setColor(Color.RED);
        g.fillRect(0, 0, getWidth(), getHeight());
        System.out.println("Width from paintComponent = " + getWidth());
      }

      @Override
      public String getToolTipText(MouseEvent event) {
        System.out.println("Width from getToolTipText = " + getWidth());
        return super.getToolTipText(event);
      }
    };

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

You can see that the component has been sized and the correct result is printed from the paintComponent method. However, when you hover your mouse over the cell in "Column 2", the getToolTipText method doesn't print the same value.

I found similar questions asked before, but the answer is generally that the Component hasn't been sized yet. In my case, the component has clearly been sized. Can someone please explain why getWidth() returns 0 in the getToolTipText method? Is there a better way to do this?

Was it helpful?

Solution

Override the getToolTipText() method of the JTable:

JTable testTable = new JTable(new Object[][]{{"Value 1", null}}, new Object[] {"Column 1", "Column 2"})
{
  @Override
  public String getToolTipText(MouseEvent event)
  {
    JTable table = (JTable)event.getSource();
    int column = table.columnAtPoint( event.getPoint() );

    if (column == 1)
    {
        int row = table.rowAtPoint( event.getPoint() );
        Rectangle r = table.getCellRect(row, column, false);
        Point p = new Point(event.getX() - r.x, event.getY() - r.y);
//          System.out.println("Width from getToolTipText = " + r.width);

        return p.toString();
    }

    return super.getToolTipText(event);
  }
};

If you want to set the tool tip in the renderer, the code should be in the getTableCellRenderComponent() method. In this case you would then need to use the MouseInfo class to get the current mouse location and convert the location to be relative to the table cell. Something like:

@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                               boolean hasFocus, int row, int column)
{
    Point pointInTable = MouseInfo.getPointerInfo().getLocation();
    SwingUtilities.convertPointFromScreen(pointInTable, table);
    Rectangle r = table.getCellRect(row, column, false);
    Point p = new Point(pointInTable.x - r.x, pointInTable.y - r.y);
    table.setToolTipText(p.toString());

  return renderer;
}

OTHER TIPS

You are seeing the result of getWidth() from the same JLabel in two different contexts:

  1. In paintComponent(), the JLabel that has been added to a CellRendererPane which invokes validate() to calculate the width.

  2. In getToolTipText(), the label accessed by the table's ToolTipManager has not been validated.

There's an example of using CellRendererPane here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top