问题
My current Java project requires me to work with dates and through my research and tinkering around I discovered the setLenient()
method is defaulted to true
. When I set it to false
I begin to have problems with my code.
I have a JFormattedTextField
intialized with a SimpleDateFormat
. For my project, I need to have /
placeholders always present so using the answer to this question, I was able to install /
s as place holders in the form of MM/dd/yyyy
When the SimpleDateFormat
is set to setLenient(false)
, and an incomplete date is entered (such as 12/34/5), and then have the focus shift away from the formatted textfield, the entire field including the /
s is removed.
When SimpleDateFormat
is set to setLenient(true)
, this doesn't happen. Instead, the incomplete entry of 12/34/5 is set to 01/03/0006
once focus is lost.
I need to be able to usesetLenient(false)
on my simple date formatter while also always having /
placeholders. I do not really know where the core issue lies in the unwanted behavior of the program and would appreciate any insight.
Simplified program concerning issue:
public class Hello implements ActionListener{
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private Date endingDate = new Date();
private String endingString = null;
private SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
private JFormattedTextField formattedText = new JFormattedTextField(dateFormatter);
private JLabel label1 = new JLabel();
private JLabel label2 = new JLabel();
private TextArea ta = new TextArea();
private Button b = new Button("click");
public Hello() {
//setPreferredSize(new Dimension(500,500));
b.addActionListener(this);
label1 = new JLabel("test");
label2 = new JLabel("test");
formattedText.setColumns(10);
dateFormatter.setLenient(false); // not efficient
try {
MaskFormatter dateMask = new MaskFormatter("##/##/####");
dateMask.install(formattedText);
} catch (ParseException ex) {
Logger.getLogger(Hello.class.getName()).log(Level.SEVERE, null, ex);
}
panel.add(formattedText);
panel.add(label1);
panel.add(label2);
panel.add(ta);
panel.add(b);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new Hello();
}
});
System.out.println("Hello, World");
}
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
System.out.println(formattedText);
endingDate = (Date) formattedText.getValue();
System.out.println(endingDate);
endingString = dateFormatter.format(endingDate);
System.out.println(endingString);
}
}
回答1:
You can use an InputVerifier that will verify the contents. If the date is not valid, you can popup a JOptionPane.
See the example below. I try to parse the input in the method isValidDate
. If it's not a valid date, it will return false, causing the InputVerifier
to return false in it's verify
method.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Box;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.text.MaskFormatter;
public class InputVerifyDate {
private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
public InputVerifyDate() {
JFormattedTextField formattedField = createFormattedTextField();
JTextField field = new JTextField(10);
format.setLenient(false);
Box box = Box.createVerticalBox();
box.add(formattedField);
box.add(Box.createVerticalStrut(10));
box.add(field);
box.setBorder(new EmptyBorder(10, 10, 10, 10));
JFrame frame = new JFrame();
frame.add(box);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JFormattedTextField createFormattedTextField() {
JFormattedTextField formattedField = null;
try {
MaskFormatter dateMask = new MaskFormatter("##/##/####");
formattedField = new JFormattedTextField(dateMask);
} catch (ParseException ex) {
Logger.getLogger(InputVerifyDate.class.getName()).log(Level.SEVERE, null, ex);
}
formattedField.setColumns(10);
formattedField.setInputVerifier(getInputVerifier());
return formattedField;
}
private InputVerifier getInputVerifier() {
InputVerifier verifier = new InputVerifier() {
@Override
public boolean verify(JComponent input) {
JFormattedTextField field = (JFormattedTextField) input;
String text = field.getText();
return isValidDate(text);
}
@Override
public boolean shouldYieldFocus(JComponent input) {
boolean valid = verify(input);
if (!valid) {
JOptionPane.showMessageDialog(null, "Please enter a valid date in format dd/mm/yyyy");
}
return valid;
}
};
return verifier;
}
public boolean isValidDate(String dateString) {
try {
format.parse(dateString);
return true;
} catch (ParseException ex) {
return false;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new InputVerifyDate();
}
});
}
}
来源:https://stackoverflow.com/questions/22914371/java-where-is-source-of-unwanted-behavior-in-my-jformattedtextfield