[英]Textfield onchange validation
我正在使用以下代码编写贷款计算器,但是当我尝试验证用户的输入时,我无法让setText运行。 我没有收到任何编译错误,只是无法正常工作。 我有以下代码:
public class LoanCalculator extends JFrame {
// Create text fields for interest rate,
// year, loan amount, monthly payment, and total payment
private JTextField jtfAnnualInterestRate = new JTextField("5");
private JTextField jtfNumberOfYears = new JTextField("10");
private JTextField jtfLoanAmount = new JTextField("10000");
private JTextField jtfMonthlyPayment = new JTextField("106.07");
private JTextField jtfTotalPayment = new JTextField("12727.86");
// Create a Compute Payment button
private JButton jbtClear = new JButton("Reset Fields");
public LoanCalculator() {
// Panel p1 to hold labels and text fields
JPanel p1 = new JPanel(new GridLayout(5, 2));
p1.add(new JLabel("Annual Interest Rate"));
p1.add(jtfAnnualInterestRate);
p1.add(new JLabel("Number of Years"));
p1.add(jtfNumberOfYears);
p1.add(new JLabel("Loan Amount"));
p1.add(jtfLoanAmount);
p1.add(new JLabel("Monthly Payment"));
p1.add(jtfMonthlyPayment);
p1.add(new JLabel("Total Payment"));
p1.add(jtfTotalPayment);
p1.setBorder(new
TitledBorder("Enter loan amount, interest rate, and year"));
jtfTotalPayment.setEditable(false);
jtfMonthlyPayment.setEditable(false);
// Panel p2 to hold the button
JPanel p2 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
p2.add(jbtClear);
// Add the panels to the frame
add(p1, BorderLayout.CENTER);
add(p2, BorderLayout.SOUTH);
// Register listeners
jbtClear.addActionListener(new ButtonListener());
jtfAnnualInterestRate.getDocument().addDocumentListener(new DocListener());
jtfNumberOfYears.getDocument().addDocumentListener(new DocListener());
jtfLoanAmount.getDocument().addDocumentListener(new DocListener());
}
/** Handle textfield changes */
class DocListener implements DocumentListener {
public void insertUpdate(DocumentEvent e) { validate(); }
public void removeUpdate(DocumentEvent e) { }
public void changedUpdate(DocumentEvent e) { }
public void validate() {
//get values from text fields
double interest = Double.parseDouble(jtfAnnualInterestRate.getText());
int year = Integer.parseInt(jtfNumberOfYears.getText());
double loanAmt = Double.parseDouble(jtfLoanAmount.getText());
Loan loan = new Loan(interest, year, loanAmt);
//validate field values and shift focus if needed
if (! (interest >= 1 && interest <= 10)){
JOptionPane.showMessageDialog(null,
"interest must be between 1 and 10 percent");
jtfAnnualInterestRate.setText("5"); //THIS DOESN'T RUN
jtfAnnualInterestRate.requestFocus(true);
}
//display monthly and total payments
else {
jtfMonthlyPayment.setText(String.format("%.2f",
loan.getMonthlyPayment()));
jtfTotalPayment.setText(String.format("%.2f",
loan.getTotalPayment()));
}
}
}
/** Handle the Reset button Code not included */
}
public static void main(String[] args) {
LoanCalculator frame = new LoanCalculator();
frame.pack();
frame.setTitle("LoanCalculator");
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
int screenWidth = screenSize.width;
int screenHeight = screenSize.height;
// Locate the upper-left corner at (x, y)
int x = 3 * (screenWidth - frame.getWidth()) / 4;
int y = (screenHeight - frame.getHeight()) /2;
frame.setLocation(x, y);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
知道我哪里出错了吗?
您不能在其自己的DocumentListener内对JTextComponent进行突变,至少不能直接对其进行突变。 我知道两种可能的解决方案:
1)将文本更改排队到Runnable内部的EDT上:
if (!(interest >= 1 && interest <= 10)) {
JOptionPane.showMessageDialog(null, "interest must be between 1 and 10 percent");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jtfAnnualInterestRate.setText("5"); // THIS DOESN'T RUN
jtfAnnualInterestRate.requestFocus(true);
}
});
2)使用DocumentFilter
编辑
关于您的问题的注意事项:
它只是不起作用。 我有以下代码:
它所做的不只是“不起作用”。 实际上,它引发了一个重要的异常,该异常准确地描述了您的代码在做什么错以及在哪里 :
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
at javax.swing.text.AbstractDocument.writeLock(Unknown Source)
at javax.swing.text.AbstractDocument.replace(Unknown Source)
at javax.swing.text.JTextComponent.setText(Unknown Source)
at pkg.LoanCalculator$DocListener.validate(LoanCalculator.java:78) // your numbers will be different
at pkg.LoanCalculator$DocListener.insertUpdate(LoanCalculator.java:58) // ditto
下次您问类似的问题时,您可能想在问题中发布信息丰富的异常堆栈跟踪。 这将帮助我们实现自我。
编辑2
同样在下一次,请尝试仅发布编译所必需且与您的问题相关的代码。 例如,您只需要发布JTextField,DocumentListener并将其显示在简单的JOptionPane中即可。 即
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class LoanCalcSscce {
protected static final double MIN_INTEREST = 0;
protected static final double MAX_INTEREST = 10;
public static void main(String[] args) {
final JTextField jtfAnnualInterestRate = new JTextField("5");
jtfAnnualInterestRate.getDocument().addDocumentListener(
new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
validate(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
validate(e);
}
@Override
public void changedUpdate(DocumentEvent e) {
validate(e);
}
public void validate(DocumentEvent e) {
final Document doc = e.getDocument();
try {
String text = doc.getText(0, doc.getLength()).trim();
double interest = Double.parseDouble(text);
if (!(interest >= MIN_INTEREST && interest <= MAX_INTEREST)) {
JOptionPane.showMessageDialog(null,
"interest must be between 1 and 10 percent");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jtfAnnualInterestRate.setText("5");
jtfAnnualInterestRate.requestFocus(true);
}
});
}
} catch (BadLocationException e1) {
e1.printStackTrace();
} catch (NumberFormatException nfe) {
// inform user and set interest to baseline.
}
}
});
JOptionPane.showMessageDialog(null, jtfAnnualInterestRate);
}
}
而且,我们可以更轻松地分析您的代码并帮助您解决它。 这称为sscce 。
编辑3
为了我的钱,我不会在DocumentListener中验证我的输入,因为这可能会在输入尚未完成时尝试验证。 当用户决定通过按下“提交”(或任何您称呼它)按钮来提交数据时,我将进行所有验证。 换句话说,我将在ActinoListener中进行验证。 例外:如果输入只能是数字,或者只能是小写字母,或者其他可以验证部分输入也很重要的东西,则可以在DocumentFilter中进行验证。
编辑4
正如MadProgrammer在评论中建议的那样,还认真考虑了使用InputVerifier作为当用户离开输入字段(此处为JTextField)时验证输入的一种不错的方法: InputVerifier教程
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.