Java Swing:如何解析一个 Phone 数字、格式化它并在 JTable 中显示它

Java Swing: How To Parse A Phone Number, Format It, And Display It In A JTable

我正在尝试将 JTable 中的 phone 数字列格式化为 (Area) Prefix-Number。我不确定我做错了什么,因为它编译时没有错误,并且根据 getTableCellRenderer 教程和我仔细研究过的其他大量示例,它应该可以工作。但它没有...它仍然被格式化为 JTable 中的一个字符串。

我首先接受来自一个文本字段的用户输入 phone 数字:

//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()) <= 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) && (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, "<html>Please fill in all required fields as denoted by the <font color='red'>*</font>.</html>");
    }
}

然后我尝试将它传递到 Phone 数字 class 以尝试解析字符串:

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;
    }
}

从那里我尝试使用对象解析器将其格式化为 CellRenderer class:

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;
    }
}

最后我尝试在 JTable 中实现新格式:

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<Patient> patients = null;

                    if (((firstName != null) && (firstName.trim().length() > 0)) ||
                        ((lastName != null) && (lastName.trim().length() > 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<Patient> patients = patientDAO.getAllPatients();
            PatientTableModel model = new PatientTableModel(patients);

            table.setModel(model);
        } catch (Exception exc) {
            JOptionPane.showMessageDialog(null, "Error: " + exc, "Error",
                    JOptionPane.ERROR_MESSAGE);
        }

    }
}

phone 号码从 MySQL databasetinytext 列中存储和检索。如果需要,请随时索取更多代码,我砍掉了很多部分来尝试缩短问题。


好吧...我完全迷路了,诚然,我是 Java Swing.I 的新手,尝试将 class Phone 编号调用到自定义 CellRenderer Class.我得到的结果是 (null) null-null。我不确定我做错了什么,我应该尝试使用 CustomCellRenderer 教程中所示的 MaskFormatter API 吗?这是折射代码:

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);
    }
}

Phone人数Class:

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;
    }
}

it compiles without errors and according to the getTableCellRenderer tutorials and other numerous examples I've poured over it should work

问题是您没有正确实现渲染器。我建议您从 Using Custom Renderers 上的 Swing 教程开始,以获取适当的示例。

您创建的方法从未被调用。 DefaultTableCellRenderer 的 getTableCellRendererComponent(...) 方法没有 PhoneNumber 作为参数。它有一个 Object.

每当你试图覆盖一个方法时,不要忘记 @Override 注释:

@Override
getTableCellRendererComponent(JTable table, PhoneNumber value, boolean isSelected, boolean hasFocus, int row, int column)

现在尝试编译你的代码,你会得到一个错误,因为你试图覆盖的方法的方法签名不存在。

要在渲染器中格式化数据,更简单的方法是覆盖渲染器的 setValue(...) 方法。代码类似于:

public class PhoneNumberRenderer extends DefaultTableCellRenderer
{
    public PhoneNumberRenderer()
    {
        super();
        setHorizontalAlignment(SwingConstants.CENTER);
    }

    @Override
    public void setValue(Object value)
    {
        if (value instanceof PhoneNumber)
        {
            PhoneNumber pn = (PhoneNumber)value;
            value = "(" + pn.areaCode + ") " + pn.prefix" + "...";
        }

        super.setValue(value);
    }
}

您可能希望在 PhoneNumber class 中创建一个 getFormattedPhoneNumber() 方法来 return 格式化字符串中的 phone 号码。其他 classes 不应该直接访问变量,在一个地方格式化数据总是一个好主意。