1

I have a JTable and I am trying to add a header tool tip that will display the string that is in the table header for each of the header cells. I can set the value of the header cell:

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

where colModel:

TableColumnModel colModel = audioTable.getColumnModel();

enter image description here enter image description here

To do this, I've added this listener:

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

        }
    });

And I see mouseMoved being printed over and over again in between this 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)

I'm not sure how to get a longer stack trace, this is how I created the table:

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

The tricky thing i am trying to do is to add column's dynamically, so i add a column each time the user populates the current column like so:

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

Is the way that I am adding the columns the problem causing this NPE?

georges
  • 175
  • 4
  • 17

1 Answers1

2

First of all, you haven't included enough code for me to figure out why the NullPointerException, but fortunately that's okay because you're approaching the problem the wrong way.

You don't need to use a MouseMotionListener at all. Swing already supports a ToolTip behavior, all you need to do is get access to the cell renderer itself. Simply set the renderer to a value that will set the ToolTipText property before rendering the component.

You haven't included enough code for me to show you how to do this in your app, but I can show you how to do it in the tutorial app from Oracle: In the initial setup, do this:

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

Here's the complete code of the demo with some of the unneeded code stripped out:

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

And a screenshot (obviously my mouse isn't captured in the screenshot):

enter image description here


You can do something similar for the ColumnHeader, by using 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;
  }
});
durron597
  • 31,968
  • 17
  • 99
  • 158
  • @georges Will the users not be able to double click the border of a header cell to auto-resize the column to fit the largest cell name? Or just click and drag? – TylerH Sep 09 '15 at 18:22
  • @durron597 was able to see the tool tip for the header, when i add it to my code though i still get the NPE. Is this not the right way to add a column maybe? TableColumn tc = new TableColumn(modelAudio.getColumnCount()); tc.setHeaderValue(" "); audioTable.addColumn(tc); modelAudio.addColumn(tc); – georges Sep 09 '15 at 19:11
  • @georges You haven't posted enough code to be able to debug the `NPE`. That particular bit of code probably wouldn't cause it. Please [edit](http://stackoverflow.com/posts/32485629/edit) your question with additional information. – durron597 Sep 09 '15 at 19:13
  • @durron597 in an effort to duplicate the problem with a subset of the code i thought relevant i cannot duplicate the NPE. Thank you for all your help, the header tool tip works on my subset i will just keep re-adding till i find the issue. Thanks again - I owe you a beer. – georges Sep 09 '15 at 20:12