title: Java Swing: How To Parse A Phone Number, Format It, And Display It In A JTable
body: <p>I am trying to format a phone number column in a <code>JTable</code> as <code>(Area) Prefix-Number</code>. I am not sure what I am doing wrong as it compiles without errors and according to the <code>getTableCellRenderer</code> tutorials and other numerous examples I've pored over it should work. But it doesn't... it is still formatted as one string in the JTable.</p>
  
  <p>I first accept user input from one text field for a phone number:</p>
  
  <pre><code>//import necessary API
  
  public class AddPatientDialog extends JDialog {
  
      private final JPanel contentPanel = new JPanel();
      private JTextField txtFieldPhneNum;
  
      private PatientDAO patientDAO;
  
      private PatientSessionTrackerApp patientSessionTrackerApp;
  
      public AddPatientDialog(PatientSessionTrackerApp thePatientSessionTracker, PatientDAO thePatientDAO) {
          this();
          patientDAO = thePatientDAO;
          patientSessionTrackerApp = thePatientSessionTracker;
      }
  
      public final class LengthRestrictedDocument extends PlainDocument {
  
            private final int limit;
  
            public LengthRestrictedDocument(int limit) {
              this.limit = limit;
            }
  
            @Override
            public void insertString(int offs, String str, AttributeSet a)
                throws BadLocationException {
              if (str == null)
                return;
  
              if ((getLength() + str.length()) &lt;= limit) {
                super.insertString(offs, str, a);
              }
            }
          }
  
      /**
       * Create the dialog.
       */
      public AddPatientDialog() {
          setSize(450, 300);
          setResizable(false);
          setTitle("Add New Patient");
          getContentPane().setLayout(new BorderLayout());
          contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
          getContentPane().add(contentPanel, BorderLayout.CENTER);
          contentPanel.setLayout(null);
          {
              JLabel lblPhneNum = new JLabel("Phone Number");
              lblPhneNum.setBounds(10, 86, 104, 14);
              contentPanel.add(lblPhneNum);
          }
  
          txtFieldPhneNum = new JTextField();
          txtFieldPhneNum.setBounds(124, 83, 86, 20);
          contentPanel.add(txtFieldPhneNum);
          txtFieldPhneNum.setColumns(10);
          txtFieldPhneNum.setDocument(new LengthRestrictedDocument(10));
  
          JPanel buttonPane = new JPanel();
          buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
          getContentPane().add(buttonPane, BorderLayout.SOUTH);
          {
              JButton okButton = new JButton("Add Patient");
              okButton.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent arg0) {
                      savePatient();
                  }
              });
              okButton.setActionCommand("OK");
              buttonPane.add(okButton);
              getRootPane().setDefaultButton(okButton);
          }
  
          JTextArea txtAddPatientWarning = new JTextArea();
          txtAddPatientWarning.setText("WARNING!!! Once a patient is created it is added to the database and cannot be removed from the database via the Patient Session Tracker. If a patient is added in error, please contact Sudo Technologies at (701) 388-3752.");
          txtAddPatientWarning.setBounds(10, 132, 424, 60);
          txtAddPatientWarning.setEditable(false);
          txtAddPatientWarning.setBackground(Color.YELLOW);
          txtAddPatientWarning.setLineWrap(true);
          contentPanel.add(txtAddPatientWarning);
  
          JLabel lblIe = new JLabel("Enter numbers only (i.e. 1234567890)");
          lblIe.setBounds(220, 86, 214, 14);
          contentPanel.add(lblIe);
      }
  
      protected void savePatient() {
  
          // get the patient info from the gui
          String firstName = txtFieldFName.getText();
          String middleName = txtFieldMName.getText();
          String lastName = txtFieldLName.getText();
          String phneNum = txtFieldPhneNum.getText();
          String email = txtFieldEmail.getText();
  
          Patient tempPatient = new Patient(phneNum);
  
          if ((firstName.trim().length() != 0) &amp;&amp; (lastName.trim().length() != 0)) {  
  
              try{
                  // save to the database
                  patientDAO.addPatient(tempPatient);
  
                  // close dialog
                  setVisible(false);
                  dispose();
  
                  // refresh gui list
                  patientSessionTrackerApp.refreshPatientsView();
  
                  // show success message
                  JOptionPane.showMessageDialog(patientSessionTrackerApp, "Patient added to the database.", 
                      "Patient Added",
                      JOptionPane.INFORMATION_MESSAGE);
              } catch (Exception exc) {
                  JOptionPane.showMessageDialog(patientSessionTrackerApp, 
                          "Error saving patient: " +
                          exc.getMessage(), "Error",
                          JOptionPane.ERROR_MESSAGE);
              } 
          } else 
              JOptionPane.showMessageDialog(patientSessionTrackerApp, "&lt;html&gt;Please fill in all required fields as denoted by the &lt;font color='red'&gt;*&lt;/font&gt;.&lt;/html&gt;");
      }
  }
  </code></pre>
  
  <p>I then try to pass it into a PhoneNumber class in order to try and parse the string:</p>
  
  <pre><code>public class PhoneNumber {
      public String areaCode;
      public String prefix;
      public String num;
  
      public PhoneNumber(String areaCode, String prefix, String num) {
          this.areaCode = areaCode;
          this.prefix = prefix;
          this.num = num;
      }
  
      public PhoneNumber() {}
  
      public PhoneNumber parsePhoneNumber(String phneNum) {
          String[] phneNumArr = {phneNum.substring(0,3), phneNum.substring(3,6), phneNum.substring(6)};
          areaCode = phneNumArr[0];
          prefix = phneNumArr[1];
          num = phneNumArr[2];
          return new PhoneNumber(areaCode, prefix, num);
      }
  
      @Override
      public String toString() {
          return "areaCode=" + areaCode + "; prefix=" + prefix + "; num=" + num;
      }
  }
  </code></pre>
  
  <p>From there I try to use the Object parser to format it in a <code>CellRenderer</code> class:</p>
  
  <pre><code>import java.awt.Component;
  
  import javax.swing.JTable;
  import javax.swing.SwingConstants;
  import javax.swing.table.DefaultTableCellRenderer;
  
  import com.patientsessiontracker.core.*;
  
  public class PatientSessionTrackerCellRenderer extends DefaultTableCellRenderer {
      private static final long serialVersionUID = 1L;
      public String areaCode;
      public String prefix;
      public String num;
      public String phneNum;
  
      public Component getTableCellRendererComponent(JTable table, PhoneNumber value, boolean isSelected, 
                                                     boolean hasFocus, int row, int column) {
          //Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
          PhoneNumber phneNum = new PhoneNumber();
          value = phneNum;
          String text =  "(" + phneNum.areaCode + ") " + phneNum.prefix + "-" + phneNum.num;
          setHorizontalAlignment(SwingConstants.CENTER);
          setText(text);
          return this;
      }
  }
  </code></pre>
  
  <p>Finally I attempt to implement the new format in the JTable:</p>
  
  <pre><code>import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.EventQueue;
  import java.awt.FlowLayout;
  
  import javax.swing.border.EmptyBorder;
  import javax.swing.JButton;
  import javax.swing.JFrame;
  import javax.swing.JLabel;
  import javax.swing.JOptionPane;
  import javax.swing.JPanel;
  import javax.swing.JTable;
  import javax.swing.JTextField;
  import javax.swing.JScrollPane;
  
  import java.util.List;
  
  import com.patientsessiontracker.core.*;
  import com.patientsessiontracker.dao.*;
  
  public class PatientSessionTrackerApp extends JFrame {
  
      private JPanel contentPane;
      private JTextField txtFieldSrchFName;
      private JButton btnSearch;
      private JScrollPane scrollPane;
      private static JTable table;
  
      private static PatientDAO patientDAO;
      private JPanel panelBtn;
      private JButton btnAddPatient;
      private JTextField txtFieldSrchLName;
  
      /**
       * Launch the application.
       */
      public static void main(String[] args) {
          EventQueue.invokeLater(new Runnable() {
              public void run() {
                  try {
                      PatientSessionTrackerApp frame = new PatientSessionTrackerApp();
                      frame.setVisible(true);
                      PatientSessionTrackerApp.refreshPatientsView();
                      table.getColumnModel().getColumn(3).setCellRenderer(new PatientSessionTrackerCellRenderer());
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          });
      }
  
      /**
       * Create the frame.
       */
      public PatientSessionTrackerApp() {
  
          // create the DAO
          try {
              patientDAO = new PatientDAO();
          } catch (Exception exc) {
              JOptionPane.showMessageDialog(this, "Error: " + exc, "Error", JOptionPane.ERROR_MESSAGE); 
          }
  
          setTitle("Patient Session Tracker");
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          setSize(600, 300);
          setResizable(false);
          contentPane = new JPanel();
          contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
          setContentPane(contentPane);
          contentPane.setLayout(null);
  
          JPanel panelSrch = new JPanel();
          panelSrch.setBounds(5, 5, 579, 33);
          contentPane.add(panelSrch);
          panelSrch.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
  
          JLabel lblFirstName = new JLabel("First Name");
          panelSrch.add(lblFirstName);
  
          txtFieldSrchFName = new JTextField();
          panelSrch.add(txtFieldSrchFName);
          txtFieldSrchFName.setColumns(13);
  
          btnSearch = new JButton("Search");
          btnSearch.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {        
  
                  try {
                      String firstName = txtFieldSrchFName.getText();
                      String lastName = txtFieldSrchLName.getText();
  
                      List&lt;Patient&gt; patients = null;
  
                      if (((firstName != null) &amp;&amp; (firstName.trim().length() &gt; 0)) ||
                          ((lastName != null) &amp;&amp; (lastName.trim().length() &gt; 0))) 
                          patients = patientDAO.searchPatients(firstName, lastName);
                      else
                          patients = patientDAO.getAllPatients();
  
                      // create the model and update the "table"
                      PatientTableModel model = new PatientTableModel(patients);
  
                      table.setModel(model);
                      table.getColumnModel().getColumn(3).setCellRenderer(new PatientSessionTrackerCellRenderer());
  
                  } catch (Exception exc) {
                      JOptionPane.showMessageDialog(PatientSessionTrackerApp.this, "Error: " + exc, "Error", JOptionPane.ERROR_MESSAGE); 
                  }
  
              }
          });
  
          JLabel lblLastName = new JLabel("Last Name");
          panelSrch.add(lblLastName);
  
          txtFieldSrchLName = new JTextField();
          panelSrch.add(txtFieldSrchLName);
          txtFieldSrchLName.setColumns(13);
          panelSrch.add(btnSearch);
  
          scrollPane = new JScrollPane();
          scrollPane.setBounds(5, 38, 579, 186);
          contentPane.add(scrollPane);
  
          table = new JTable();
          scrollPane.setViewportView(table);
  
          panelBtn = new JPanel();
          panelBtn.setBounds(5, 224, 579, 38);
          contentPane.add(panelBtn);
  
          btnAddPatient = new JButton("Add Patient");
          btnAddPatient.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
                  // create dialog
                  AddPatientDialog addPatient = new AddPatientDialog(PatientSessionTrackerApp.this, patientDAO);
  
                  // show dialog
                  addPatient.setModal(true);
                  addPatient.setVisible(true);
              }
          });
          panelBtn.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
          panelBtn.add(btnAddPatient);
      }
  
      public static void refreshPatientsView() {
  
          try {
              List&lt;Patient&gt; patients = patientDAO.getAllPatients();
              PatientTableModel model = new PatientTableModel(patients);
  
              table.setModel(model);
          } catch (Exception exc) {
              JOptionPane.showMessageDialog(null, "Error: " + exc, "Error",
                      JOptionPane.ERROR_MESSAGE);
          }
  
      }
  }
  </code></pre>
  
  <p>The phone number gets stored and retrieved from a <code>tinytext</code> column in the <code>MySQL database</code>. Feel free to ask for more code if needed, I hacked a lot of parts out to try and shorten the question.</p>
  
  <hr>
  
  <p>Okay... I am completely lost and admittedly a noob to Java Swing.I tried invoking the class Phone Number into the Custom CellRenderer Class. What I get for a result is (null) null-null. I'm not sure what I am doing wrong, should I try using the MaskFormatter API as shown in the CustomCellRenderer tutorial? Here is the refractored code:</p>
  
  <pre><code>CustomCellRenderer:
  public class PatientSessionTrackerCellRenderer extends DefaultTableCellRenderer {
      private static final long serialVersionUID = 1L;
  
      public PatientSessionTrackerCellRenderer() {
          super();
          setHorizontalAlignment(SwingConstants.CENTER);
      }
  
      @Override
      public void setValue(Object value) {
          PhoneNumber phneNum = new PhoneNumber();
          value.toString();
          value =  "(" + phneNum.areaCode + ") " + phneNum.prefix + "-" + phneNum.num;
  
          super.setValue(value);
      }
  }
  </code></pre>
  
  <p>PhoneNumber Class:</p>
  
  <pre><code>public class PhoneNumber {
      public String areaCode;
      public String prefix;
      public String num;
  
      private PhoneNumber(String areaCode, String prefix, String num) {
          this.areaCode = areaCode;
          this.prefix = prefix;
          this.num = num;
      }
  
      public PhoneNumber() {}
  
      public PhoneNumber parsePhoneNumber(String value) {
          String[] phneNumArr = {value.substring(0,3), value.substring(3,6), value.substring(6)};
          areaCode = phneNumArr[0];
          prefix = phneNumArr[1];
          num = phneNumArr[2];
          return new PhoneNumber(areaCode, prefix, num);
      }
  
      @Override
      public String toString() {
          return "areaCode=" + areaCode + "; prefix=" + prefix + "; num=" + num;
      }
  }
  </code></pre>