Component.getWidth()在不同的上下文中返回0

时间:2013-06-06 22:50:45

标签: java swing jtable tooltip tablecellrenderer

我有一个自定义TableCellRenderer我希望根据鼠标位于单元格中的位置显示不同的工具提示。我遇到的问题是getWidth()0调用时始终返回getToolTipText

这是一个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;
    }
  }
}

您可以看到组件已调整大小,并且从paintComponent方法打印了正确的结果。但是,当您将鼠标悬停在“第2列”中的单元格上时,getToolTipText方法不会打印相同的值。

我之前发现了类似的问题,但答案通常是Component尚未调整大小。就我而言,该组件的大小明显。有人可以解释为什么getWidth()会在0方法中返回getToolTipText吗?有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

覆盖JTable的getToolTipText()方法:

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

如果要在渲染器中设置工具提示,则代码应位于getTableCellRenderComponent()方法中。在这种情况下,您需要使用MouseInfo类来获取当前鼠标位置并将位置转换为相对于表格单元格。类似的东西:

@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;
}

答案 1 :(得分:2)

您在两个不同的背景下看到来自同一getWidth()的{​​{1}}的结果:

  1. JLabel中,paintComponent()已添加到JLabel调用CellRendererPane来计算宽度。

  2. validate()中,表格getToolTipText()访问的标签尚未经过验证。

  3. 有一个使用ToolTipManager here的例子。