如何将 Table Header 生成的工具提示添加到我的 JTable 单元格?

How do I add a Tool Tip generated from the Table Header to my JTable cells?

我有一个 JTable,我正在尝试添加一个 header 工具提示,它将显示 table header 中每个 header 中的字符串] 细胞。我可以设置 header 单元格的值:

colModel.getColumn(currentColumn).setHeaderValue(time + "(s)");

其中 colModel:

TableColumnModel colModel = audioTable.getColumnModel();

为此,我添加了这个侦听器:

audioTable = new JTable(modelAudio);
    JTableHeader header = audioTable.getTableHeader();
    header.addMouseMotionListener(new MouseMotionListener() {

        @Override
        public void mouseMoved(MouseEvent e) {
            System.out.println("mouseMoved");
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseDragged(MouseEvent e) {
            System.out.println("mouseDragged");
            // TODO Auto-generated method stub

        }
    });

而且我看到 mouseMoved 在此 NPE 之间被一遍又一遍地打印:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableHeaderUI$HeaderRenderer.getTableCellRendererComponent(Unknown Source)
at javax.swing.table.JTableHeader.getToolTipText(Unknown Source)
at javax.swing.ToolTipManager$insideTimerAction.actionPerformed(Unknown Source)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

我不确定如何获得更长的堆栈跟踪,这就是我创建 table:

的方式
modelAudio = new DefaultTableModel();
modelAudio.addColumn(" ");
audioTable = new JTable(modelAudio);

我想做的棘手的事情是动态添加列,所以每次用户填充当前列时我都会添加一列,如下所示:

TableColumn tc = new TableColumn(modelAudio.getColumnCount());
tc.setHeaderValue(" ");
audioTable.addColumn(tc);
modelAudio.addColumn(tc);

我添加列的方式是否是导致此 NPE 的问题?

首先,您没有包含足够的代码让我弄清楚 NullPointerException 的原因,但幸运的是这没关系,因为您以错误的方式解决问题。

您根本不需要使用 MouseMotionListener。 Swing 已经支持 ToolTip 行为,您需要做的就是访问单元格渲染器本身。只需将渲染器设置为将在渲染组件之前设置 ToolTipText 属性 的值。

你没有包含足够的代码让我向你展示如何在你的应用程序中执行此操作,但我可以向你展示如何在 tutorial app from Oracle: 在初始设置中执行此操作:

final TableCellRenderer renderer = table.getDefaultRenderer(Object.class);
table.setDefaultRenderer(Object.class, new TableCellRenderer() {
  @Override
  public Component getTableCellRendererComponent(JTable table,
      Object value, boolean isSelected, boolean hasFocus, int row,
      int column) {
    Component component = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    String columnHeader = table.getColumnModel().getColumn(column).getHeaderValue().toString();
    ((JComponent) component).setToolTipText(columnHeader);
    return component;
  }
});

以下是删除了一些不需要的代码的完整演示代码:

import javax.swing.*;
import javax.swing.table.TableCellRenderer;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;

public class SimpleTableDemo extends JPanel {

  public SimpleTableDemo() {
    super(new GridLayout(1, 0));

    String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years",
        "Vegetarian" };

    Object[][] data = {
        { "Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false) },
        { "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
        { "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
        { "Jane", "White", "Speed reading", new Integer(20), new Boolean(true) },
        { "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };

    final JTable table = new JTable(data, columnNames);
    table.setPreferredScrollableViewportSize(new Dimension(500, 70));
    table.setFillsViewportHeight(true);

    final TableCellRenderer renderer = table.getDefaultRenderer(Object.class);
    table.setDefaultRenderer(Object.class, new TableCellRenderer() {
      @Override
      public Component getTableCellRendererComponent(JTable table,
          Object value, boolean isSelected, boolean hasFocus, int row,
          int column) {
        Component component = renderer.getTableCellRendererComponent(table,
            value, isSelected, hasFocus, row, column);
        String columnHeader = table.getColumnModel().getColumn(column)
            .getHeaderValue().toString();
        ((JComponent) component).setToolTipText(columnHeader);
        return component;
      }
    });

    // Create the scroll pane and add the table to it.
    JScrollPane scrollPane = new JScrollPane(table);

    // Add the scroll pane to this panel.
    add(scrollPane);
  }

  private static void createAndShowGUI() {
    // Create and set up the window.
    JFrame frame = new JFrame("SimpleTableDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // Create and set up the content pane.
    SimpleTableDemo newContentPane = new SimpleTableDemo();
    newContentPane.setOpaque(true); // content panes must be opaque
    frame.setContentPane(newContentPane);

    // Display the window.
    frame.pack();
    frame.setVisible(true);
  }

  public static void main(String[] args) {
    // Schedule a job for the event-dispatching thread:
    // creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
}

还有一张截图(显然我的鼠标没有被截图):


您可以为 ColumnHeader 执行类似的操作,方法是使用 table.getTableHeader().getDefaultRenderer():

final TableCellRenderer header = table.getTableHeader().getDefaultRenderer();
table.getTableHeader().setDefaultRenderer(new TableCellRenderer() {
  @Override
  public Component getTableCellRendererComponent(JTable table,
      Object value, boolean isSelected, boolean hasFocus, int row,
      int column) {
    Component tableCellRendererComponent = header.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    String columnHeader = table.getColumnModel().getColumn(column)
        .getHeaderValue().toString();
    ((JComponent) tableCellRendererComponent).setToolTipText(columnHeader);
    return tableCellRendererComponent;
  }
});