0

JTable ヘッダーにツールチップを追加しようとしています。この場合、JTableHeader Java クラスを拡張する TTHeader クラスを使用します。すべて問題ないように見えますが、JTable に新しい TTHeader ヘッダーを追加しようとすると、ソースが不明な NullPointerException が発生します。どうしてか分かりません。TTHeader クラスは問題ないようです。問題は別の場所にあります。

これが私のアプローチのコードです。JTable populate の場合:

 private JPanel contentPane;
 private JScrollPane scrollPane;
 private JTable table;
 private String tooltipsSDB[] = {"SessionID", "UserID", "PatientID", "PluginID", "Date", "Time"};

 Connection conn = null;
 ResultSet rs = null;
 PreparedStatement ps = null;

 Table() {
      // Connection Component
      conn = ConnectionJDBC.ConnectDB();

      setTitle("My sample table");
      setSize(new Dimension(400, 400));
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setLocationRelativeTo(null);
      setVisible(true);

      contentPane = new JPanel();
      contentPane.setLayout(new BorderLayout(0, 0));
      setContentPane(contentPane);

      scrollPane = new JScrollPane();
      contentPane.add(scrollPane, BorderLayout.CENTER);

      table = new JTable() {
           public boolean isCellEditable(int row, int column) {
                return false;
           };
      };
      table.setAutoCreateRowSorter(true);
      // Populate JTable with data from SQL DB
      populateTable();
      scrollPane.setViewportView(table);
 }

 public void populateTable() {
      String sql = "SELECT * FROM " + ExampleDatabase + " ORDER BY " + ExampleData + " DESC";
      try {
           // Make Connection With DB
           ps = conn.prepareStatement(sql);
           rs = ps.executeQuery();
           ResultSetMetaData rsmetadata = rs.getMetaData();

           // Populate JTable
           int columns = rsmetadata.getColumnCount();
           DefaultTableModel dtm = new DefaultTableModel();
           Vector columns_name = new Vector();
           Vector data_rows = new Vector();
           for (int i = 1; i <= columns; i++) {
                columns_name.addElement(rsmetadata.getColumnName(i));
           }
           dtm.setColumnIdentifiers(columns_name);
           while (rs.next()) {
                data_rows = new Vector();
                for (int j = 1; j <= columns; j++) {
                     data_rows.addElement(rs.getString(j));
                }
                dtm.addRow(data_rows);
           }
           table.setModel(dtm);

           // Create Header For JTable
           TTHeader tth = new TTHeader(table.getColumnModel());
           tth.setToolTipStrings(tooltipsSDB);
           table.setTableHeader(tth); // On This Line I Get NullPointerException With Uknown Source

           table.repaint();
      } catch (SQLException e) {
           JOptionPane.showMessageDialog(null, "Populate table error! \n" + e);

      } 
 }

 public static void main(String args[]) {
      EventQueue.invokeLater(new Runnable() {
           public void run() {
                try {
                     new Table();
                } catch (Exception e) {
                     JOptionPane.showMessageDialog(null, e);
                }
           }
      });
 }

そして TTHeader クラス:

String[] toolTips;

public TTHeader(TableColumnModel model) {
    super(model);
}

public String getToolTipText(MouseEvent e) {
    int col = columnAtPoint(e.getPoint());
    int modelCol = getTable().convertColumnIndexToModel(col);
    String retStr;
    try {
        retStr = toolTips[modelCol];
    } catch (NullPointerException ex) {
        retStr = "";
    } catch (ArrayIndexOutOfBoundsException ex) {
        retStr = "";
    }
    if (retStr.length() < 1) {
        retStr = super.getToolTipText(e);
    }
    return retStr;
}

public void setToolTipStrings(String[] toolTips) {
    this.toolTips = toolTips;
}

JComboBox から 2 番目のデータベースを選択すると、NPE が表示されます。JComboBox リスナーで populateTable() メソッドを呼び出します。より具体的なスタックトレースは次のとおりです。

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at mypackage.TTHeader.getToolTipText(TTHeader.java:19)
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$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$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)

行番号 19:

int modelCol = getTable().convertColumnIndexToModel(col);
4

1 に答える 1

1

NPE を取得して行を特定したら、最初に確認することは、逆参照演算子 ( .) のすべての出現です。そのような演算子の左側 (!) の値は になりますnull。(1 つの行に複数.の s がある場合は、そのうちの 1 つです。したがって、行がである場合は、 isまたはreturnsfoo.getBar().doSomething()のいずれかです。しかし、返されるものは問題ではありません。)foonullfoo.getBar()nulldoSomething()

この場合、おそらくgetTable()を返すメソッドになりますnull

Java 5 以降、NPE の 2 つの新しい、かなり卑劣な原因が考えられます。

  1. の暗黙的な逆参照。ここでは、が nullfor (Foo foo : fooCollection)の場合に NPE を取得します。fooCollection
  2. 数字の自動アンボックス:Integer i = null; int j = i + 1; //NPE here

一般的な NPE のデバッグについて知っておく必要があるのはこれだけです。もちろん、変数値をログに記録するか、デバッガーを使用してコードを段階的に実行する必要があるという、さらに一般的なアドバイスもあります。

于 2013-09-24T16:45:36.493 に答える