10 Replies Latest reply on Jun 7, 2007 5:20 AM by 843806

    Different cell editor in single column - Bug?

    843806
      Hello all,
      In a single column, I wish to have different cell editor. By refering to,

      http://groups.google.com.my/group/comp.lang.java.gui/browse_thread/thread/9944682df9c2ca5f/2adbd3e46e19e521?lnk=st&q=Tablemodel+cell+class+type&rnum=7#2adbd3e46e19e521
      http://forum.java.sun.com/thread.jspa?forumID=257&threadID=211873

      I manage to do the following implementation :
      package org.yccheok.jstock.gui;
      
      import javax.swing.event.*;
      import javax.swing.table.*;
      import javax.swing.*;
      import java.awt.*;
      import java.awt.event.*;
      import org.yccheok.jstock.engine.*;
      
      import org.apache.commons.logging.Log;
      import org.apache.commons.logging.LogFactory;
      
      /**
       *
       * @author yccheok
       */
      public class IndicatorJTable extends JTable {
          
          /** Creates a new instance of IndicatorJTable */
          public IndicatorJTable() {
          }
          
          public TableCellRenderer getCellRenderer(int row, int column) {        
              final int modelRow = this.convertRowIndexToModel(row);
              final int modelcolumn = this.convertColumnIndexToModel(column);
      
              return this.getDefaultRenderer(getModel().getValueAt(modelRow, modelcolumn).getClass());
          }
      
          @Override
          public TableCellEditor getCellEditor(int row, int column) {
              final int modelRow = this.convertRowIndexToModel(row);
              final int modelcolumn = this.convertColumnIndexToModel(column);
              
              return this.getDefaultEditor(getModel().getValueAt(modelRow, modelcolumn).getClass());
          }
      
          private static final Log log = LogFactory.getLog(IndicatorJTable.class);
      }
      with my own custom Table model.

      When the JTable first display, it look fine. The cell which is being specific as Double.class type, the display is correct :


      Double, Float � same as Number, but the object-to-text translation is performed by a NumberFormat instance (using the default number format for the current locale).


      When I double click on the cell specific as Double.class, and try to enter non-numerical value and press enter, there suppose to be a red border around, and doesn't allow my newly enter non-double value to be written to the table. However, that is not the case, I am able to write non-double value into the cell which is specific as Double.class type.

      I realize that my overridden getCellRenderer and getCellEditor in JTable, able to return me a correct Double type renderer and cell editor. However, the getColumnClass in table model, is unable to return class specific to a particular cell. When editing process start, JTable will also try to query information from Table Model getColumnClass, which in turn will return String (Of course, I just cann't make the particular column to return class Double. There are other cell which is not Double)
          public Class getColumnClass(int c) {
              return super.getColumnClass(c);        
          }
      This make the editing process behave incorrect. Please refer to the following bug database.

      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4801881

      May I know does any of you figure out a workaround on this?

      Thank you very much!

      cheok
        • 1. Re: Different cell editor in single column - Bug?
          camickr
          Haven't though it through but maybe you could override the getColumnClass(..) method to also use the getSelectedRow() method of JTable.
          • 2. Re: Different cell editor in single column - Bug?
            843806
            Hem... but isn't that table model should not access JTable directly? That will break the initial MVC design.
            • 3. Re: Different cell editor in single column - Bug?
              camickr
              JTable also has a getColumnClass(..) methed.
              • 4. Re: Different cell editor in single column - Bug?
                843806
                OK. Let's take the following examples. In my JTable, all the cells should be Object, except one of it (at col=1, row=1) should be Double.

                When I mean a cell should be Double, it means the following :

                1. I key in a non double value in the particular cell and try to press enter to update my table model. It is not allowed and will display red border around the cell as follow:
                http://yancheng.cheok.googlepages.com/invalid-double-when-press-enter.JPG

                2. I key in a double value in the particular cell and try to press enter. Everything is ok as follow:
                http://yancheng.cheok.googlepages.com/double-when-press-enter.JPG


                I try two methods to achieve my objective. However, neither one does work. When I key in non double value and press enter, the following exception will be thrown :

                Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot format given Object as a Number
                at java.text.DecimalFormat.format(DecimalFormat.java:487)
                at java.text.Format.format(Format.java:140)


                First method
                ---------------
                package javaapplication7;
                
                import javax.swing.*;
                import javax.swing.table.*;
                
                /**
                 *
                 * @author YC Cheok
                 */
                public class MyTable extends JTable {
                    
                    /** Creates a new instance of MyTable */
                    public MyTable() {
                    }
                    
                    public TableCellEditor getCellEditor(int row, int column) {
                        if(row == 1 && column == 1) {
                            return this.getDefaultEditor(Double.class);
                        }
                        
                        return super.getCellEditor(row, column);    
                    }
                    
                    public TableCellRenderer getCellRenderer(int row, int column) {
                        if(row == 1 && column == 1) {
                            return this.getDefaultRenderer(Double.class);
                        }
                        
                        return super.getCellRenderer(row, column);    
                    }    
                }
                
                package javaapplication7;
                
                /**
                 *
                 * @author  YC Cheok
                 */
                public class NewJFrame extends javax.swing.JFrame {
                    
                    /** Creates new form NewJFrame */
                    public NewJFrame() {
                        initComponents();
                    }
                    
                    /** This method is called from within the constructor to
                     * initialize the form.
                     * WARNING: Do NOT modify this code. The content of this method is
                     * always regenerated by the Form Editor.
                     */
                    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">                          
                    private void initComponents() {
                        jScrollPane1 = new javax.swing.JScrollPane();
                        jTable1 = new MyTable();
                
                        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
                        jTable1.setModel(new javax.swing.table.DefaultTableModel(
                            new Object [][] {
                                {null, null, null, null},
                                {null, null, null, null},
                                {null, null, null, null},
                                {null, null, null, null}
                            },
                            new String [] {
                                "Title 1", "Title 2", "Title 3", "Title 4"
                            }
                        ));
                        jScrollPane1.setViewportView(jTable1);
                
                        getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);
                
                        pack();
                    }// </editor-fold>                        
                    
                    /**
                     * @param args the command line arguments
                     */
                    public static void main(String args[]) {
                        java.awt.EventQueue.invokeLater(new Runnable() {
                            public void run() {
                                new NewJFrame().setVisible(true);
                            }
                        });
                    }
                    
                    // Variables declaration - do not modify                     
                    private javax.swing.JScrollPane jScrollPane1;
                    private javax.swing.JTable jTable1;
                    // End of variables declaration                   
                    
                }
                Second Method
                -------------
                package javaapplication7;
                
                import javax.swing.*;
                import javax.swing.table.*;
                import javax.swing.table.DefaultTableCellRenderer;
                
                /**
                 *
                 * @author YC Cheok
                 */
                public class MyTable extends JTable {
                    
                    /** Creates a new instance of MyTable */
                    public MyTable() {
                        final TableCellEditor oldEditor = this.getDefaultEditor(Object.class);
                        final TableCellRenderer oldRenderer = this.getDefaultRenderer(Object.class);
                        
                        javax.swing.DefaultCellEditor editor = new javax.swing.DefaultCellEditor(new JTextField()) {
                            public java.awt.Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
                                if(row == 1 && column == 1) {
                                    TableCellEditor e = table.getDefaultEditor(Double.class);
                                    return e.getTableCellEditorComponent(table, value, isSelected, row, column);
                                }
                                
                                return oldEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
                            }
                        };
                
                        javax.swing.table.DefaultTableCellRenderer renderer = new javax.swing.table.DefaultTableCellRenderer() {
                            public java.awt.Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                                if(row == 1 && column == 1) {
                                    TableCellRenderer e = table.getDefaultRenderer(Double.class);
                                    return e.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                                }
                                
                                return oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                            }
                        };
                        
                        this.setDefaultEditor(Object.class, editor);        
                        this.setDefaultRenderer(Object.class, renderer);
                    }   
                }
                Message was edited by:
                KwangHooi
                • 5. Re: Different cell editor in single column - Bug?
                  camickr
                  Overriding the getColumnClass() method of JTable appear to work fine for me.
                  • 6. Re: Different cell editor in single column - Bug?
                    843806
                    Yes. I try to overriden the JTable getColumnClass couple with getSelectedRow. It "almost" work. But, still have flaw.

                    The flaw can be easily reproduced using the following senario:


                    1. Double click on the cell of the first row, first col, make it editable (You can see a cursor blinking)

                    2. Do not press enter.

                    3. Perform a single click on the cell of the second row, second col (The one we intend to make it as Double)

                    Once again, we can see the following error :

                    Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot format given Object as a Number
                    at java.text.DecimalFormat.format(DecimalFormat.java:487)
                    at java.text.Format.format(Format.java:140)
                    at javax.swing.JTable$DoubleRenderer.setValue(JTable.java:5301)

                    ...

                    package javaapplication7;
                     
                    import javax.swing.*;
                    import javax.swing.table.*;
                     
                    /**
                     *
                     * @author YC Cheok
                     */
                    public class MyTable extends JTable {
                        
                        /** Creates a new instance of MyTable */
                        public MyTable() {
                        }
                        
                        public TableCellEditor getCellEditor(int row, int column) {
                            if(row == 1 && column == 1) {
                                return this.getDefaultEditor(Double.class);
                            }        
                            return super.getCellEditor(row, column);    
                        }
                        
                        public Class getColumnClass(int column) {
                            // if(this.getSelectedRow() == 1 && this.getSelectedColumn() == 1) {
                            if(this.getSelectedRow() == 1 && column == 1) {
                                System.out.println("hacking");
                                return Double.class;        
                            }
                            
                            return this.getModel().getColumnClass(this.convertColumnIndexToModel(column));
                        }
                        
                        public TableCellRenderer getCellRenderer(int row, int column) {
                            if(row == 1 && column == 1) {
                                return this.getDefaultRenderer(Double.class);
                            }
                            
                            return super.getCellRenderer(row, column);    
                        }    
                    }
                    • 7. Re: Different cell editor in single column - Bug?
                      camickr
                      It appears the the getSelectedRow() doesn't always return the expected value. So here's a work around that seems to work:
                              JTable table = new JTable(data, columnNames)
                              {
                                  private int renderingRow;
                      
                                  //  Returning the Class of each column will allow different
                                  //  renderers and editors to be used based on Class
                      
                                  public Class getColumnClass(int column)
                                  {
                                      if(column == 2 && renderingRow == 0)
                                      {
                                              return Double.class;
                                      }
                      
                                      return super.getColumnClass( column );
                                  }
                      
                                  public TableCellEditor getCellEditor(int row, int column)
                                  {
                                      renderingRow = row;
                      
                                      if(row == 0 && column == 2)
                                      {
                                          return this.getDefaultEditor(Double.class);
                                      }
                                      return super.getCellEditor(row, column);
                                  }
                      
                                  public TableCellRenderer getCellRenderer(int row, int column)
                                  {
                                      renderingRow = row;
                      
                                      if(row == 0 && column == 2)
                                      {
                                          return this.getDefaultRenderer(Double.class);
                                      }
                      
                                      return super.getCellRenderer(row, column);
                                  }
                              };
                      • 8. Re: Different cell editor in single column - Bug?
                        843806
                        Why don't you use this
                        table.getColumn(columnIdentifier).setCellEditor(yourEditor);
                        you can also obtain column from table's columnModel by index.

                        regards,
                        Stas
                        • 9. Re: Different cell editor in single column - Bug?
                          843806
                          Yes. I had tested with camickr suggestion. Although it seems more like a hacking workaround, It does work :)

                          Thanks!
                          • 10. Re: Different cell editor in single column - Bug?
                            843806
                            table.getColumn(columnIdentifier).setCellEditor(yourEditor);
                            This will setup an editor in per column basic. The cell editor itself still need to perform row checking, in order to return correct component in per cell basic. At the end, the solution should be end up with my tested "Second method"

                            I think we need to some fix in the table model design, so that we can achieve the objective "Different cell editor in single column" in a "clean" way :)