Java 如何将从表格标题生成的工具提示添加到JTable单元格?

Java 如何将从表格标题生成的工具提示添加到JTable单元格?,java,swing,jtable,tooltip,jtableheader,Java,Swing,Jtable,Tooltip,Jtableheader,我有一个JTable,我正在尝试添加一个header工具提示,该提示将显示每个header单元格的表头中的字符串。我可以设置标题单元格的值: colModel.getColumn(currentColumn.setHeaderValue(time+“(s)”) 其中colModel: TableColumnModel colModel = audioTable.getColumnModel(); 为此,我添加了以下侦听器: audioTable = new JTable(modelAudi

我有一个JTable,我正在尝试添加一个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.access$400(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.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)
我不确定如何获得更长的堆栈跟踪,我就是这样创建表的:

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已经支持
工具提示
行为,只需访问单元渲染器本身即可。只需将渲染器设置为一个值,该值将在渲染组件之前设置
ToolTipText
属性

您没有包含足够的代码,我无法向您演示如何在应用程序中执行此操作,但我可以在中向您演示如何在初始设置中执行此操作,请执行以下操作:

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();
      }
    });
  }
}
还有一个屏幕截图(很明显,屏幕截图中没有捕捉到我的鼠标):


通过使用
table.getTableHeader().getDefaultRenderer()
,可以对
列标题执行类似操作:


@georges用户不能双击标题单元格的边框来自动调整列的大小以适应最大的单元格名称吗?还是单击并拖动?@durron597能够看到标题的工具提示,当我将其添加到我的代码中时,尽管我仍然得到了NPE。这不是添加列的正确方法吗?TableColumn tc=新的TableColumn(modelAudio.getColumnCount());tc.setHeaderValue(“”);audioTable.addColumn(tc);modelAudio.addColumn(tc)@georges您没有发布足够的代码来调试
NPE
。这段特殊的代码可能不会导致它。请用附加信息回答您的问题。@durron597为了用我认为相关的代码子集复制问题,我无法复制NPE。感谢您的帮助,标题工具提示对我的子集有效,我将继续添加,直到找到问题。再次感谢-我欠你一杯啤酒。
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;
  }
});