JTable

if(myTable.getValueAt(1,1) != null)
  // process the cell;

/// JFrame Constructor
public NewJFrame() {
        initComponents();
        // add a listener to  jTable1 that will call a method whenever data has changed.
        jTable1.getModel().addTableModelListener(new TableModelListener() {
             public void tableChanged(TableModelEvent e) {
                if(e.getType() == TableModelEvent.UPDATE)
                    cellChanged(e.getFirstRow(), e.getColumn());
           }
         });

    }
//
// method to call when a cell has changed
//
public void cellChanged(int row, int column)
{  
     System.out.println("cell "+row+","+column+" changed");
}

Other notes:

You'll notice that when you write code to process a button click this code will not get any value from the cell the user is currently working on. The problem is the little editor attached to the cell doesn't store the value in the cell until focus is shifted to another editing window (other cell or JTextField). This won't happen when menu items or buttons are clicked on (this allows things like cancel buttons to work even though someone isn't finished editing a cell, or the cell has invalid contents and doesn't want the focus to be shifted away).

The way it works is the table stores objects (Strings, Integers, Doubles) in each cell. Initially each cell has a null object.  You should provide a default value for each cell (do this with the table model dialog or with a for loop in your constructor code). Without a default value, its possible when you access a cell's value you may get null back instead of an object (resulting in a null pointer exception). When a user is changing a cell he/she is actually typing into a small edit window (not the cell itself, though it looks that way), when editing focus is shifted away from that editing window, then the editing window verifies the contents against the data type, if the contents are ok, then a object of the proper type is created and stored in the cell itself. If the contents are not ok (i.e. you specified that the column was to be of type Double and they entered "cat"), then the box is highlighted in red AND WHAT IS STORED IN THE CELL IS NOT CHANGED (any value that was there before is still there). At that point the user has the ability to fix the mistake or press the ESC key to restore the old value.

Because of this, when you process a menu or button press event, and a cell is being edited, then you will not get the value the user is currently typing in, intead you will get the old value (which might be null if you didn't setup default values for the cells). To get around this, all you have to do is to tell the JTable to edit a different cell.
Do this by using the editCellAt(row,col)  command in your button processing method.  Use -1,-1 or a cell you know to be safe. Note, this will force the little edit window to store what the user is currently typing into the cell (in unless the contents do not match the data type, in that event you get the old value and the user will see the value they are currently working on outlined in red). You can then access the value using getValueAt

   private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:
       jTable1.editCellAt(-1,-1);  // force editing to cease, storing work in progress
       String s1 = jTable1.getValueAt(0,0).toString();
       String s2 = jTable1.getValueAt(0,1).toString();
       String s3 = jTable1.getValueAt(0,2).toString();
       System.out.println(s1+"   "+s2+"   "+s3);
    }

 An alternate solution to editCellAt, is to tell the table to stop editing, do this by calling editingCanceled with a change event. You'll need to import javax.swing.event.*; See below.

       jTable1.editingCanceled(new ChangeEvent(jTable1));

The draw back to this solution is that current editing changes are discarded (valid or invalid), and the documentation does not recommend calling this from within your program (though they did make the method public and it does seem to work). The advantage to editingCanceled is the table is left displaying the values you used in processing the button press, but since good values may be discarded, the user will likely be annoyed.

NimbusLookAndFeel - As of version 7, Netbeans added code to JFrame Applications to use the Nimbus Look and Feel as opposed to the default or system look and feel.  Unfortunately, past versions of Nimbus has/had errors, some of which could effect JTables.  To get rid of the Nimbus look and feell all you need to do is to delete a section of code from the main method of your JFrame application. Delete the code in red, don't delete the other lines in the method.

public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }



Examples of processing JTables:
assume your JTable is named theTable and the cells are formatted as Integers
/*
* set all the table entries to zero
*/
for(int row = 0; row < theTable.getRowCount(); row++)
{
   for(int col = 0; col < theTable.getColumnCount(); col++)
    {
       theTable.setValueAt(0,row,col); // set the cell to a integer 0 (0.0 sets it to a double 0)
     }
 }

/*
 * print all the row values to the output window
*/
for(int row = 0; row < theTable.getRowCount(); row++)
{
   for(int col = 0; col < theTable.getColumnCount(); col++)
    {
     if(
theTable.getValueAt(row,col) != null)
     {
      Integer aCell = (Integer)theTable.getValueAt(row,col);
      System.out.print(aCell+", ");
      }
    }
     System.out.println(""); // print a carriage return at the end of each row
 }

/*
 * calculate and print the average value of each row to the output window
*/
for(int row = 0; row < theTable.getRowCount(); row++)
{
   int sum = 0, average = 0;
   for(int col = 0; col < theTable.getColumnCount(); col++)
    {
      if(theTable.getValueAt(row,col) != null)
      {

        Integer aCell = (Integer)theTable.getValueAt(row,col);
        sum = sum + aCell;
      }
     }
     average = sum / theTable.getColumnCount();
     System.out.println("  average = "+average); // prints average of each row, null values are assumed to be 0
 }



JTable Model Objects


DefaultTableModel

Examples:

    private void clearTableButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
    int rows = theTable.getRowCount();
    int columns = theTable.getColumnCount();
    for(int r = 0; r < rows; r++)
        for(int c = 0; c < columns; c++)
            theTable.setValueAt("",r,c);
    }

    private void removeRowButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
        DefaultTableModel model = (DefaultTableModel)theTable.getModel();  // get the table model
        int row = theTable.getSelectedRow();
        if(row >= 0)
            model.removeRow(row);
    }

    private void addColumnButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
        DefaultTableModel model = (DefaultTableModel)theTable.getModel();  // get the table model
        int columncount = model.getColumnCount();
        model.addColumn("Column "+(columncount+1));  // add a new column
       
    }

    private void addRowButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
        DefaultTableModel model = (DefaultTableModel)theTable.getModel();  // get the table model
        int colcount = theTable.getColumnCount();  // ask how many columns
        Object data[] = new Object[colcount];  // create an empty data array
        model.addRow(data);  // add the data as a new row
    }
   



Printing JTables


the JTable component has a built in Print method that will all you to send the contents of the JTablet to a printer.  Its not necessary to use PrinterJob or PageFormat objects, just call one of the print method variations.  Simple example:

   try{
          jTable1.print(javax.swing.JTable.PrintMode.FIT_WIDTH); 
    }
    catch(Exception ex)
    {
       JOptionPane.showMessageDialog(this,"Printing failed :"+ex.getMessage());
      }

in this example the JTable is printed such that the it will fit on one page width, but may span mutliple pages.  Instead of using FIT_WIDTH as the print mode you could use NORMAL, in that case the table could span multiple pages in width.

Print modes

FIT_WIDTH - Printing mode that scales the output smaller, if necessary, to fit the table's entire width (and thereby all columns) on each page; Rows are spread across multiple pages as necessary.

NORMAL - Printing mode that prints the table at its current size, spreading both columns and rows across multiple pages if necessary.

You can also printout headers and footers on each page, e.g.

try{
        MessageFormat header = new MessageFormat("Header Printout of my data ");
        MessageFormat footer = new MessageFormat("Footer ....");
        jTable1.print(javax.swing.JTable.PrintMode.FIT_WIDTH, header, footer);
        }
        catch(Exception ex)
        {
          JOptionPane.showMessageDialog(this,"Printing failed :"+ex.getMessage());
        }