Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6429812

NPE after calling JTable.updateUI() when using a header renderer + XP L&F

XMLWordPrintable

    • b26
    • x86
    • windows

      FULL PRODUCT VERSION :
      jre1.5.0_06

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      When using a JTable with a custom header renderer and the WinXP L&F, calling JTable.updateUI() prior to the first call of setVisible(true) on the containing window will cause a NullPointerException to be thrown from the painting thread.

      Please note that this is possibly the same bug as 5049957, but I am reporting it because of the following differences in with the previous bug decription:

      - User is not required to "hot swap" out the XP theme in the control panel while the application is running to reproduce the error.

      - The error only occurs if updateUI() is called before the window is displayed for the first time.

      - Unlike bug 5049957 , the error is NOT caused by the skin pointer in XPDefaultRenderer being set to null. After running the code with in my debuger, I discovered that after the call to updateUI(), the skin field pointer is (correctly) non-null. Rather the header member variable of the outer class (WindowsTableHeaderUI) is made null by the updateUI() call. This is what appears to be causing the NPE. Therefore the fix described in 5049957 would likely not work.



      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile the attached test program. Two YES/NO boxes will appear. Selecting YES to both methods will cause the error.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The window and tables appear normally.
      ACTUAL -
      The painter thread throws an exception, causing only part of the window to be rendered correctly.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
      at com.sun.java.swing.plaf.windows.WindowsTableHeaderUI$XPDefaultRenderer.paint(Unknown Source)
      at javax.swing.CellRendererPane.paintComponent(Unknown Source)
      at javax.swing.plaf.basic.BasicTableHeaderUI.paintCell(Unknown Source)
      at javax.swing.plaf.basic.BasicTableHeaderUI.paint(Unknown Source)
      at javax.swing.plaf.ComponentUI.update(Unknown Source)
      at javax.swing.JComponent.paintComponent(Unknown Source)
      at javax.swing.JComponent.paint(Unknown Source)
      at javax.swing.JComponent.paintChildren(Unknown Source)
      at javax.swing.JComponent.paint(Unknown Source)
      at javax.swing.JViewport.paint(Unknown Source)
      at javax.swing.JComponent.paintChildren(Unknown Source)
      at javax.swing.JComponent.paint(Unknown Source)
      at javax.swing.JComponent.paintChildren(Unknown Source)
      at javax.swing.JComponent.paint(Unknown Source)
      at javax.swing.JComponent.paintChildren(Unknown Source)
      at javax.swing.JComponent.paint(Unknown Source)
      at javax.swing.JLayeredPane.paint(Unknown Source)
      at javax.swing.JComponent.paintChildren(Unknown Source)
      at javax.swing.JComponent.paintWithOffscreenBuffer(Unknown Source)
      at javax.swing.JComponent.paintDoubleBuffered(Unknown Source)
      at javax.swing.JComponent.paint(Unknown Source)
      at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
      at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
      at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
      at java.awt.Container.paint(Unknown Source)
      at sun.awt.RepaintArea.paintComponent(Unknown Source)
      at sun.awt.RepaintArea.paint(Unknown Source)
      at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
      at java.awt.Component.dispatchEventImpl(Unknown Source)
      at java.awt.Container.dispatchEventImpl(Unknown Source)
      at java.awt.Window.dispatchEventImpl(Unknown Source)
      at java.awt.Component.dispatchEvent(Unknown Source)
      at java.awt.EventQueue.dispatchEvent(Unknown Source)
      at java.awt.EventDispatchThread.pumpOneEventForHierarchy(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)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.*;
      import javax.swing.*;
      import javax.swing.table.*;

      public class TestFrame extends JFrame {

      public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedLookAndFeelException{
      int res = JOptionPane.showConfirmDialog(null,"Do you want to use the XP L&F?","laffo",JOptionPane.YES_NO_OPTION);
      if (res == JOptionPane.YES_OPTION)
      UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
      new TestFrame().setVisible(true);
      }

      public class MyModel extends AbstractTableModel {

      public int getRowCount() {
      return 10;
      }

      public int getColumnCount() {
      return 10;
      }

      public Object getValueAt(int rowIndex, int columnIndex) {
      return ""+rowIndex + " X " + columnIndex;
      }

      }

      public class MyJTable extends JTable {
      /**
      *
      */
      private static final long serialVersionUID = -233098459210523146L;

      public MyJTable(TableModel model){
      super(model);
      }

      public void doSomething(){
      System.out.println("HEHE");
      }
      }


      private JPanel jContentPane = null;
      private JScrollPane jScrollPane = null;
      private JTable table1 = null;
      private JScrollPane jScrollPane1 = null;
      private JTable table2 = null;
      /**
      * This is the default constructor
      */
      public TestFrame() {
      super();
      initialize();
      int res = JOptionPane.showConfirmDialog(null,"Do you want to call updateUI() on the tables ?","laffo",JOptionPane.YES_NO_OPTION);
      if (res == JOptionPane.YES_OPTION){
      table2.updateUI();
      table1.updateUI();
      }
      }

      /**
      * This method initializes this
      *
      * @return void
      */
      private void initialize() {
      this.setSize(753, 658);
      this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
      this.setContentPane(getJContentPane());
      this.setTitle("JFrame");
      }

      /**
      * This method initializes jContentPane
      *
      * @return javax.swing.JPanel
      */
      private JPanel getJContentPane() {
      if (jContentPane == null) {
      jContentPane = new JPanel();
      jContentPane.setLayout(null);
      jContentPane.add(getJScrollPane(), null);
      jContentPane.add(getJScrollPane1(), null);
      }
      return jContentPane;
      }

      /**
      * This method initializes jScrollPane
      *
      * @return javax.swing.JScrollPane
      */
      private JScrollPane getJScrollPane() {
      if (jScrollPane == null) {
      jScrollPane = new JScrollPane();
      jScrollPane.setBounds(new java.awt.Rectangle(358,0,387,618));
      jScrollPane.setViewportView(getTable1());
      }
      return jScrollPane;
      }

      /**
      * This method initializes table1
      *
      * @return javax.swing.JTable
      */
      private JTable getTable1() {
      if (table1 == null) {
      table1 = new JTable(new MyModel());
      }
      return table1;
      }

      /**
      * This method initializes jScrollPane1
      *
      * @return javax.swing.JScrollPane
      */
      private JScrollPane getJScrollPane1() {
      if (jScrollPane1 == null) {
      jScrollPane1 = new JScrollPane();
      jScrollPane1.setBounds(new java.awt.Rectangle(0,0,350,618));
      jScrollPane1.setViewportView(getTable2());
      }
      return jScrollPane1;
      }

      /**
      * This method initializes table2
      *
      * @return javax.swing.JTable
      */
      private JTable getTable2() {
      if (table2 == null) {
      table2 = new MyJTable(new MyModel());
      JTableHeader header = table2.getTableHeader();
      TableCellRenderer render = new DecoratedHeaderRenderer(header.getDefaultRenderer());
      header.setDefaultRenderer(render);
      }
      return table2;
      }


      private class DecoratedHeaderRenderer implements TableCellRenderer {

      public DecoratedHeaderRenderer(TableCellRenderer render){
      this.render = render;
      }
      private TableCellRenderer render;
      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
      Component c = render.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
      return c;
      }

      }

      } // @jve:decl-index=0:visual-constraint="10,10"

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      - Do not use custom table header renderers while working with the XP L&F.

            tr Tejesh R
            igor Igor Nekrestyanov (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: