classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] FYI: Implementing multiple editors for JTable (with example


From: Meskauskas Audrius
Subject: [cp-patches] FYI: Implementing multiple editors for JTable (with example)
Date: Thu, 19 Jan 2006 13:36:42 +0100
User-agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)

This patch add the multi-editor support for JTable. The table now supports the two editors: text and boolean. The boolean values are rendered and edited using JCheckBox.

I add the more complicated table example to the Swing demo to show the table with header, multiple data types (text and boolean at the moment) and placed int the scroll window. The editing seems working as expected but the attempt to scroll transiently displays the old (unedited) values. As any forced repainting (resizing, temporary obstruction with other window) displays the updated values again, this may be the problem somewhere in the JScrollPane.

2006-01-19  Audrius Meskauskas  <address@hidden>

   * javax/swing/JTable.java (editingStopped, editingCancelled):
   Repaint the edited cell.
   (setValueAt): Do not add the value object to this container.
   (editorTimer, rowBeingEdited, columnBeingEdited, oldCellValue): Removed.
       (editingStopped): Use editingRow, editingColumn and not
   rowBeingEdited, columnBeingEdited. (editValueAt): rewritten.
   (doLayout): Move the editor component, if present, into the new
   location and call repaint(). (moveToCellBeingEdited): new method.
   (TableTextField): new inner class.
   (getDefaultEditor): Instantiante TableTextField, not JTextField.
   (setValueAt): Repaint the changed segment.
       (createDefaultEditors): Implemented.
(BooleanCellRenderer): Center the checkbox and use the default foreground and background colors. * javax/swing/plaf/basic/BasicTableUI.java (paintCell): Do not paint the caret here. Do not accept unused parameters. (paint): No need to allocate rectangle for each cell. * javax/swing/DefaultCellEditor.java: Rewritten. * examples/gnu/classpath/examples/swing/Demo.java (mkTable):
     Use TableDemo.java table example.
   * examples/gnu/classpath/examples/swing/TableDemo.java: New file.
Index: javax/swing/DefaultCellEditor.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/DefaultCellEditor.java,v
retrieving revision 1.17
diff -u -r1.17 DefaultCellEditor.java
--- javax/swing/DefaultCellEditor.java  16 Jan 2006 12:36:50 -0000      1.17
+++ javax/swing/DefaultCellEditor.java  19 Jan 2006 12:13:08 -0000
@@ -59,8 +59,7 @@
  * some standard object types.
  * 
  * @author Andrew Selkirk
- *
- * @status mostly unimplemented
+ * @author Audrius Meskauskas
  */
 public class DefaultCellEditor
   extends AbstractCellEditor
@@ -76,10 +75,13 @@
   protected class EditorDelegate
     implements ActionListener, ItemListener, Serializable
   {
+    /**
+     * Use the serial version UID for interoperability.
+     */
     private static final long serialVersionUID = -1420007406015481933L;
 
     /**
-     * value
+     * The object value (updated when getting and setting the value).
      */
     protected Object value;
 
@@ -90,28 +92,30 @@
     {
       // Nothing to do here.
     }
-
+    
     /**
-     * setValue
+     * Set the value for the editor component. This method is normally
+     * overridden to set the value in the way, specific for the text
+     * component, check box or combo box.
      *
-     * @param value TODO
+     * @param aValue the value to set (String, Boolean or Number).
      */
-    public void setValue(Object value)
+    public void setValue(Object aValue)
     {
-      // TODO: should be setting the value in the editorComp
-      this.value = value;
+      value = aValue;
     }
 
-   /**
-     * getCellEditorValue
-     * 
-     * @returns Object
+    /**
+     * Get the value for the editor component. This method is normally
+     * overridden to obtain the value in the way, specific for the text
+     * component, check box or combo box.
+     *
+     * @return value the value of the component (String, Boolean or Number).
      */
     public Object getCellEditorValue()
     {
-      // TODO: should be getting the updated value from the editorComp
       return value;
-    } // getCellEditorValue()
+    } 
 
     /**
      * isCellEditable
@@ -208,16 +212,132 @@
         listeners[index].editingCanceled(changeEvent);
     }
   } // EditorDelegate
+  
+  /**
+   * Provides getter and setter methods to work with the text component.
+   * 
+   * @author Audrius Meskauskas (address@hidden)
+   */
+  private class JTextFieldDelegate extends EditorDelegate
+  {
+    /**
+     * Use the serial version UID for interoperability.
+     */
+    private static final long serialVersionUID = 1;
+    
+    /**
+     * Set the value for the editor component.
+     *
+     * @param aValue the value to set (toString() will be called).
+     */
+    public void setValue(Object aValue)
+    {
+      value = aValue;
+      JTextField f = (JTextField) editorComponent;
+      if (value == null)
+        f.setText("");
+      else
+        f.setText(value.toString());
+    }
 
-       /**
+    /**
+     * Get the value for the editor component. 
+     *
+     * @return value the value of the component (String)
+     */
+    public Object getCellEditorValue()
+    {
+      JTextField f = (JTextField) editorComponent;
+      return value = f.getText();      
+    }     
+  }
+
+  /**
+   * Provides getter and setter methods to work with the combo box.
+   * 
+   * @author Audrius Meskauskas (address@hidden) 
+   */
+  private class JComboBoxDelegate extends EditorDelegate
+  {
+    /**
+     * Use the serial version UID for interoperability.
+     */
+    private static final long serialVersionUID = 1;
+    
+    /**
+     * Set the value for the editor component.
+     *
+     * @param aValue the value to set.
+     */
+    public void setValue(Object aValue)
+    {
+      value = aValue;      
+      JComboBox c = (JComboBox) editorComponent;
+      if (value != null)
+        c.setSelectedItem(value);
+    }
+
+    /**
+     * Get the value for the editor component. 
+     *
+     * @return value the value of the component (as String)
+     */
+    public Object getCellEditorValue()
+    {
+      JComboBox c = (JComboBox) editorComponent;
+      return value = c.getSelectedItem();
+    }     
+  }
+
+  /**
+   * Provides getter and setter methods to work with the check box.
+   * 
+   * @author Audrius Meskauskas (address@hidden) 
+   */
+  private class JCheckBoxDelegate extends EditorDelegate
+  {
+    /**
+     * Use the serial version UID for interoperability.
+     */
+    private static final long serialVersionUID = 1;
+    
+    /**
+     * Set the value for the editor component.
+     *
+     * @param value the value to set (must be Boolean).
+     */
+    public void setValue(Object value)
+    {
+      JCheckBox c = (JCheckBox) editorComponent;
+      
+      if (value == null)
+        c.setSelected(false);
+      else
+        c.setSelected( ((Boolean) value).booleanValue());
+    }
+
+    /**
+     * Get the value for the editor component. 
+     *
+     * @return value the value of the component (must be CharSequence)
+     */
+    public Object getCellEditorValue()
+    {
+      JCheckBox c = (JCheckBox) editorComponent;
+      value = c.isSelected() ? Boolean.TRUE : Boolean.FALSE;
+      return value;
+    }     
+  }
+  
+  /**
    * editorComponent
    */
   protected JComponent editorComponent;
 
   /**
-   * The editor delegate (normally intialised only once).
+   * The editor delegate.
    */
-  protected EditorDelegate delegate = new EditorDelegate();
+  protected EditorDelegate delegate;
 
   /**
    * clickCountToStart
@@ -225,36 +345,44 @@
   protected int clickCountToStart;
 
   /**
-   * Constructor DefaultCellEditor
+   * Create the DefaultCellEditor that uses the text field as its editor
+   * component (appropriate for the text content)
    * 
-   * @param textfield TODO
+   * @param the text field as will be used as the editor component.
    */
   public DefaultCellEditor(JTextField textfield)
   {
     editorComponent = textfield;
     clickCountToStart = 2;
+    delegate = new JTextFieldDelegate();
+    textfield.addActionListener(delegate);
   } // DefaultCellEditor()
 
   /**
-   * Constructor DefaultCellEditor
+   * Constructor DefaultCellEditor that uses the checkbox (appropriate
+   * for boolean values)
    * 
-   * @param checkbox TODO
+   * @param checkbox the checkbox that will be used with this editor.
    */
   public DefaultCellEditor(JCheckBox checkbox)
   {
     editorComponent = checkbox;
     clickCountToStart = 1;
+    delegate = new JCheckBoxDelegate();
+    checkbox.addActionListener(delegate);
   } // DefaultCellEditor()
 
   /**
-   * Constructor DefaultCellEditor
+   * Constructor DefaultCellEditor that uses the combo box.
    * 
-   * @param combobox TODO
+   * @param combobox the combo box that will be used with this editor.
    */
   public DefaultCellEditor(JComboBox combobox)
   {
     editorComponent = combobox;
     clickCountToStart = 1;
+    delegate = new JComboBoxDelegate();
+    combobox.addActionListener(delegate);
   } // DefaultCellEditor()
 
   /**
@@ -403,42 +531,9 @@
   {
     // NOTE: as specified by Sun, we don't call new() everytime, we return 
     // editorComponent on each call to getTableCellEditorComponent or
-    // getTreeCellEditorComponent.  
-    if (editorComponent instanceof JTextField)
-      prepareAsJTextField(value);
+    // getTreeCellEditorComponent.
+    delegate.setValue(value);
     return editorComponent;
   } // getTableCellEditorComponent()
-  
-  /**
-   * Prepare the editorComponent as the text field.
-   * 
-   * @param value the value of the cell before editin.
-   */
-  private void prepareAsJTextField(Object value)
-  {
-    JTextField f = (JTextField) editorComponent;
-    if (value != null)
-      f.setText(value.toString());
-    else
-      // Default null to the empty string.
-      f.setText("");
-
-    // Do not register our listener again and again (resource leak).
-    ActionListener[] l = f.getActionListeners();
-    
-    boolean have = false;
-    for (int i = 0; i < l.length; i++)
-      {
-        // We cannot just remove all listeners as the user listeners 
-        // may be registered.
-        if (l[i]==delegate)
-          {
-            have = true;
-            break;
-          }
-      }
-    if (!have)
-      f.addActionListener(delegate);
-  }
 
 }
Index: javax/swing/JTable.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTable.java,v
retrieving revision 1.65
diff -u -r1.65 JTable.java
--- javax/swing/JTable.java     16 Jan 2006 12:36:50 -0000      1.65
+++ javax/swing/JTable.java     19 Jan 2006 11:41:38 -0000
@@ -588,7 +588,7 @@
         return lastColumn;
       }
     }
-
+   
     /**
      * Creates a new <code>AccessibleJTable</code>.
      *
@@ -1006,11 +1006,30 @@
   private class BooleanCellRenderer
     extends DefaultTableCellRenderer
   {
-
     /**
      * The CheckBox that is used for rendering.
      */
-    private JCheckBox checkBox = new JCheckBox();
+    private final JCheckBox checkBox = new JCheckBox();
+    
+    /**
+     * The check box must have the text field background and be centered.
+     */
+    private BooleanCellRenderer()
+    {
+      // Render the checkbox identically as the text field.
+      JTextField f = new JTextField();
+      checkBox.setForeground(f.getForeground());
+      checkBox.setBackground(f.getBackground());
+      checkBox.setHorizontalAlignment(SwingConstants.CENTER);      
+    }
+    
+    /**
+     * Get the check box.
+     */
+    JCheckBox getCheckBox()
+    {
+      return checkBox;
+    }
 
     /**
      * Returns the component that is used for rendering the value.
@@ -1029,8 +1048,14 @@
                                                    boolean hasFocus, int row,
                                                    int column)
     {
-      Boolean boolValue = (Boolean) value;
-      checkBox.setSelected(boolValue.booleanValue());
+      // Null is rendered as false.
+      if (value == null)
+        checkBox.setSelected(false);
+      else
+        {
+          Boolean boolValue = (Boolean) value;
+          checkBox.setSelected(boolValue.booleanValue());
+        }
       return checkBox;
     }
   }
@@ -1204,8 +1229,47 @@
       return this;
     }
   }
+  
+    /**
+     * The JTable text component (used in editing) always has the table
+     * as its parent. The scrollRectToVisible must be adjusted taking the
+     * relative component position.
+     *
+     * @author Audrius Meskauskas (address@hidden)
+     */
+    private class TableTextField extends JTextField
+    {
+      /**
+       * Create the text field without the border.
+       */
+      TableTextField()
+      {
+        setBorder(null);
+      }
+      
+      /**
+       * Scroll the table, making the given rectangle of this component
+       * visible. Mind the component position with relate to the table. 
+       * With not this method overridden, the scroll pane scrolls to the
+       * top left cornec (untranslated position of the caret) after the first
+       * keystroke.
+       */
+      public void scrollRectToVisible(Rectangle r)
+      {
+        // In private class we known that the rectangle data will not be
+        // reused and we need not to clone it.
+        r.translate(getX(), getY());
+        super.scrollRectToVisible(r);
+      }
+    }    
+  
 
   private static final long serialVersionUID = 3876025080382781659L;
+  
+  /**
+   * This table, for referring identically name methods from inner classes.
+   */
+  final JTable this_table = this;
 
 
   /**
@@ -1477,27 +1541,6 @@
   protected JTableHeader tableHeader;
 
   /**
-   * The row of the cell being edited.
-   */
-  int rowBeingEdited = -1;
-
-  /**
-   * The column of the cell being edited.
-   */
-  int columnBeingEdited = -1;
-
-  /**
-   * The action listener for the editor's Timer.
-   */
-  Timer editorTimer = new EditorUpdateTimer();
-
-  /**
-   * Stores the old value of a cell before it was edited, in case
-   * editing is cancelled
-   */
-  Object oldCellValue;
-
-  /**
    * The property handler for this table's columns.
    */
   TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler =
@@ -1691,10 +1734,17 @@
     columnModel.addColumn(column);
     column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
   }
-
+  
+  /**
+   * Create the default editors for this table. The default method creates
+   * the editor for Booleans.
+   * 
+   * Other fields are edited as strings at the moment.
+   */
   protected void createDefaultEditors()
   {
-    //FIXME: Create the editor object.
+    JCheckBox box = new BooleanCellRenderer().getCheckBox();
+    setDefaultEditor(Boolean.class, new DefaultCellEditor(box));
   }
 
   protected void createDefaultRenderers()
@@ -1771,6 +1821,7 @@
     if (editorComp!=null)
       {
         remove(editorComp);
+        repaint(editorComp.getBounds());        
         editorComp = null;
       }
   }
@@ -1785,16 +1836,9 @@
   {
     if (editorComp!=null)
       {
-        remove(editorComp);
-        if (editorComp instanceof JTextField)
-          {
-            JTextField f = (JTextField) editorComp;
-            setValueAt(f.getText(), rowBeingEdited, columnBeingEdited);        
    
-          }
-        else
-          {
-            /** TODO FIXME Handle the editor types other than text field. */
-          }
+        remove(editorComp);        
+        setValueAt(cellEditor.getCellEditorValue(), editingRow, 
editingColumn);            
+        repaint(editorComp.getBounds());
         editorComp = null;
       }
     requestFocusInWindow();
@@ -2019,10 +2063,7 @@
       return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
     else
       {
-       // FIXME: We have at least an editor for Object.class in our defaults.
-        // The text field is without the border.
-        JTextField t = new JTextField();
-        t.setBorder(null);
+        JTextField t = new TableTextField();        
         TableCellEditor r = new DefaultCellEditor(t);
         defaultEditorsByColumnClass.put(columnClass, r);
         return r;
@@ -2972,6 +3013,14 @@
           cols[i] = columnModel.getColumn(i);
         distributeSpill(cols, spill);        
       }
+    
+    if (editorComp!=null)
+      moveToCellBeingEdited(editorComp);
+    
+    // Repaint fixes the invalid view after the first keystroke if the cell
+    // editing is started immediately after the program start or cell
+    // resizing. 
+    repaint();
   }
   
   /**
@@ -2981,7 +3030,7 @@
   {
     doLayout();
   }
-
+  
   /**
    * Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
    */
@@ -3164,10 +3213,9 @@
   {
     if (!isCellEditable(row, column))
       return;
-
-    if (value instanceof Component)
-      add((Component)value);
     dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
+    
+    repaint(getCellRect(row, column, true));
   }
 
   public TableColumn getColumn(Object identifier)
@@ -3275,36 +3323,40 @@
     if (isEditing())
       editingStopped(new ChangeEvent("editingStopped"));
     
-    // Select the row being edited.
-    getSelectionModel().setSelectionInterval(row, row);
-    oldCellValue = getValueAt(row, column);
+    editingRow = row;
+    editingColumn = column;
+
     setCellEditor(getCellEditor(row, column));
     editorComp = prepareEditor(cellEditor, row, column);
-    rowBeingEdited = row;
-    columnBeingEdited = column;
-    
-    if (editorComp instanceof JTextField)
-      {
-        JTextField t = (JTextField) editorComp;
-        Rectangle r = getCellRect(row, column, true);
-        // Place the text field so that it would not touch the table
-        // border.
-        int m = getRowMargin();
-        r.translate(m,m);
-        r.width-=m;
-        t.setBounds(r);
-        add(t);
-        t.requestFocusInWindow(false);
-      }
-    else
-      {
-        /** TODO FIXME editor component type is still resticted to JTextField 
*/
-      }
     
+    // Remove the previous editor components, if present. Only one
+    // editor component at time is allowed in the table.
+    removeAll();
+    add(editorComp);    
+    moveToCellBeingEdited(editorComp);
+    scrollRectToVisible(editorComp.getBounds());
+    editorComp.requestFocusInWindow();
     return true;
   }
 
   /**
+   * Move the given component under the cell being edited. 
+   * The table must be in the editing mode.
+   * 
+   * @param component the component to move.
+   */
+  private void moveToCellBeingEdited(Component component)
+  {
+     Rectangle r = getCellRect(editingRow, editingColumn, true);
+     // Place the text field so that it would not touch the table
+     // border.
+     int m = getRowMargin();
+     r.translate(m,m);
+     r.width-=m;
+     component.setBounds(r);
+  }
+
+  /**
    * Programmatically starts editing the specified cell.
    *
    * @param row the row of the cell to edit.
@@ -3362,7 +3414,7 @@
     // TODO: Implement functionality of this property (in UI impl).
     surrendersFocusOnKeystroke = value;
   }
-
+  
   /**
    * Returns whether cell editors of this table should receive keyboard focus
    * when the editor is activated by a keystroke. The default setting is
Index: javax/swing/plaf/basic/BasicTableUI.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTableUI.java,v
retrieving revision 1.39
diff -u -r1.39 BasicTableUI.java
--- javax/swing/plaf/basic/BasicTableUI.java    16 Jan 2006 12:36:50 -0000      
1.39
+++ javax/swing/plaf/basic/BasicTableUI.java    18 Jan 2006 16:14:16 -0000
@@ -1214,28 +1214,12 @@
    * system beginning at <code>(0,0)</code> in the upper left corner of the
    * table
    * @param rend A cell renderer to paint with
-   * @param data The data to provide to the cell renderer
-   * @param rowLead The lead selection for the rows of the table.
-   * @param colLead The lead selection for the columns of the table.
    */
   void paintCell(Graphics g, int row, int col, Rectangle bounds,
-                 TableCellRenderer rend, TableModel data,
-                 int rowLead, int colLead)
+                 TableCellRenderer rend)
   {
     Component comp = table.prepareRenderer(rend, row, col);
     rendererPane.paintComponent(g, comp, table, bounds);
-
-    // FIXME: this is manual painting of the Caret, why doesn't the 
-    // JTextField take care of this itself?
-    if (comp instanceof JTextField)
-      {
-        Rectangle oldClip = g.getClipBounds();
-        g.translate(bounds.x, bounds.y);
-        g.clipRect(0, 0, bounds.width, bounds.height);
-        ((JTextField)comp).getCaret().paint(g);
-        g.translate(-bounds.x, -bounds.y);
-        g.setClip(oldClip);
-      }
   }
   
   public void paint(Graphics gfx, JComponent ignored) 
@@ -1256,7 +1240,8 @@
     Dimension gap = table.getIntercellSpacing();
     int ymax = clip.y + clip.height;
     int xmax = clip.x + clip.width;
-
+    Rectangle bounds = new Rectangle();
+    
     // paint the cell contents
     for (int c = 0; c < ncols && x < xmax; ++c)
       {
@@ -1265,18 +1250,16 @@
         int width = col.getWidth();
         int halfGapWidth = gap.width / 2;
         int halfGapHeight = gap.height / 2;
+        
         for (int r = 0; r < nrows && y < ymax; ++r)
           {
-            Rectangle bounds = new Rectangle(x + halfGapWidth,
-                                             y + halfGapHeight + 1,
-                                             width - gap.width + 1,
-                                             height - gap.height);
+            bounds.x = x + halfGapWidth;
+            bounds.y = y + halfGapHeight + 1;
+            bounds.width = width - gap.width + 1;
+            bounds.height = height - gap.height;
             if (bounds.intersects(clip))
               {           
-                paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c),
-                          table.getModel(),
-                          table.getSelectionModel().getLeadSelectionIndex(),
-                          
table.getColumnModel().getSelectionModel().getLeadSelectionIndex());
+                paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c));
               }
             y += height;
           }
Index: examples/gnu/classpath/examples/swing/Demo.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/examples/gnu/classpath/examples/swing/Demo.java,v
retrieving revision 1.29
diff -u -r1.29 Demo.java
--- examples/gnu/classpath/examples/swing/Demo.java     14 Nov 2005 10:44:00 
-0000      1.29
+++ examples/gnu/classpath/examples/swing/Demo.java     18 Jan 2006 16:49:54 
-0000
@@ -987,27 +987,14 @@
     
     return tree;
   }
-
-  private static JTable mkTable()
+  
+  /**
+   * Make a sample table component.
+   */
+  private static JPanel mkTable()
   {
-    Object[][] tableData = new Object[][] {
-      {
-        "Field 1", "Field 2" , "Field 3"
-      },
-      {
-        "Field 4", "Field 5" , "Field 6"
-      },
-      {
-        "Field 7", "Field 8" , "Field 9"
-      },
-      {
-        "Field 10", "Field 11" , "Field 12"
-      }
-    };
-    Object[] columnNames = new Object[] {"Column 1", "Column 2", "Column 3"};
-
-    JTable table = new JTable(tableData, columnNames);
-    return table;
+    return new TableDemo("Table demo, double click to edit")
+                      .createContent();
   }
   
   private JPanel mkButtonBar()
/* TableDemo.java -- Demonstrates the use of JTable.
   Copyright (C) 2006 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package gnu.classpath.examples.swing;

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 * Displays the editable table. The first column consists of check boxes.
 * 
 * @author Audrius Meskauskas (address@hidden)
 */
public class TableDemo extends JFrame
{ 
  /**
   * The initial row count for this table.
   */ 
  static int rows = 32;
  
  /**
   * The initial column count for this table.
   */ 
  static int cols = 8;
  
  
  /**
   * The table model.
   */
  class TModel extends DefaultTableModel
  {
    
    /**
     * Return true if the cell is editable. All cells are editable.
     */
    public boolean isCellEditable(int parm1, int parm2)
    {
      return true;
    }
    
    /**
     * Get the number of the table rows.
     */
    public int getRowCount()
    {
      return rows;
    }

    /**
     * Get the number of the table columns.
     */
    public int getColumnCount()
    {
      return cols;
    }
    
    /**
     * Set the value at the given position
     */
    public void setValueAt(Object aValue, int aRow, int aColumn)
    {
      values[aRow][aColumn] = aValue;
    }
    
    /**
     * Get the value at the given position.
     */
    public Object getValueAt(int aRow, int aColumn)
    {
      return values[aRow][aColumn];
    }
    
    /**
     * The column name.
     */
    public String getColumnName(int column)
    {
     return "Demo "+column;
    }
    
    /**
     * The first column contains booleans, others - default class.
     */
    public Class getColumnClass(int column)
    {
      if (column == 0)
        return Boolean.class;
      else
        return super.getColumnClass(column);
    }    
  }
  
  /**
   * The table being displayed.
   */
  JTable table = new JTable();
  
  /**
   * The table model.
   */
  TModel model = new TModel();

  /**
   * The table value array.
   */
  Object[][] values;
  
  /**
   * Create the table demo with the given titel.
   * 
   * @param title the frame title.
   */
  public TableDemo(String title)
  {
    super(title);
    getContentPane().add(createContent(), BorderLayout.CENTER);
  }
  
  /**
   * Returns a panel with the demo content. The panel uses a BorderLayout(), and
   * the BorderLayout.SOUTH area is empty, to allow callers to add controls to
   * the bottom of the panel if they want to (a close button is added if this
   * demo is being run as a standalone demo).
   */
  JPanel createContent()
  {
    JPanel p = new JPanel();
    p.setLayout(new BorderLayout());
    table.setModel(model);
    values = new Object[rows][];
    for (int i = 0; i < values.length; i++)
      {
        values[i] = new Object[cols];
        for (int j = 1; j < cols; j++)
          {
            values[i][j] = "" + ((char) ('a' + j)) + i;
          }
        values [i][0] = i % 2 == 0? Boolean.TRUE : Boolean.FALSE;
      }

    // Create the table, place it into scroll pane and place
    // the pane into this frame.
    JScrollPane scroll = new JScrollPane();
    
    // The horizontal scroll bar is never needed.
    scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    scroll.getViewport().add(table);
    p.add(scroll, BorderLayout.CENTER);
    return p;
  }
  
  /**
   * The executable method to display the editable table.
   * 
   * @param args
   *          unused.
   */
  public static void main(String[] args)
  {
    TableDemo frame = new TableDemo("Table double click on the cell to edit.");
    frame.setSize(new Dimension(640, 100));
    frame.validate();
    frame.setVisible(true);
  }
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]