Swing/NumberFormatter のバックアップの現在との差分(No.2)
TITLE:JSpinnerで無効な値の入力を許可しない
Posted by terai at 2010-03-08
JSpinnerで無効な値の入力を許可しない
JSpinnerからJFormattedTextFieldを取得し、これに無効な値の入力を許可しないように設定します。- category: swing folder: NumberFormatter title: JSpinnerで無効な値の入力を許可しない tags: [JSpinner, JFormattedTextField, SpinnerNumberModel, DocumentListener, NumberFormatter] author: aterai pubdate: 2010-03-08T15:39:14+09:00 description: JSpinnerからJFormattedTextFieldを取得し、これに無効な値の入力を許可しないように設定します。 image:
概要
JSpinner
からJFormattedTextField
を取得し、これに無効な値の入力を許可しないように設定します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
#screenshot
サンプルコード
#spanend
#spanadd
JSpinner spinner = new JSpinner(makeSpinnerNumberModel());
#spanend
#spanadd
JSpinner.DefaultEditor editor =
#spanend
(JSpinner.DefaultEditor) spinner.getEditor();
#spanadd
JFormattedTextField.AbstractFormatter formatter =
#spanend
editor.getTextField().getFormatter();
#spanadd
if (formatter instanceof DefaultFormatter) {
#spanend
((DefaultFormatter) formatter).setAllowsInvalid(false);
#spanadd
}
#spanend
#spanadd
View in GitHub: Java, Kotlinサンプルコード
解説
上記のサンプルでは、DefaultFormatter#setAllowsInvalid(false)
などを設定したDefaultFormatterFactory
を作成して、JSpinner
から取得したJFormattedTextField
にsetFormatterFactory(...)
メソッドで追加しています。
- 上
-
SpinnerNumberModel
を設定した通常のJSpinner
- 別コンポーネントにフォーカスが移動するときに値が有効か無効かを判断
-
- 中
-
SpinnerNumberModel
を設定し数値以外の無効な文字入力ができないようにしたJSpinner
-
- 下
-
SpinnerNumberModel
を設定した通常のJSpinner
- 別コンポーネントにフォーカスが移動するときに値が有効か無効かを判断
- 無効な値の場合は背景色を変更
-
#spandel
JSpinner.NumberEditor editor = (JSpinner.NumberEditor)spinner.getEditor();
#spanend
#spandel
editor.getTextField().setFormatterFactory(makeFFactory(m));
#spanend
#spandel
//DefaultFormatter formatter = (DefaultFormatter) editor.getTextField().getFormatter();
#spanend
#spandel
//formatter.setAllowsInvalid(false);
#spanend
#spandel
private static JSpinner makeSpinner2(SpinnerNumberModel m) {
JSpinner s = new JSpinner(m); JSpinner.NumberEditor editor = (JSpinner.NumberEditor) s.getEditor(); JFormattedTextField ftf = (JFormattedTextField) editor.getTextField(); ftf.setFormatterFactory(makeFFactory(m)); ftf.getDocument().addDocumentListener(new DocumentListener() { private final Color color = new Color(255, 200, 200); @Override public void changedUpdate(DocumentEvent e) { updateEditValid(); }
#spanend
#spandel
private static DefaultFormatterFactory makeFFactory(final SpinnerNumberModel m) {
#spanend
final NumberFormat format = new DecimalFormat("####0");
@Override public void insertUpdate(DocumentEvent e) {
updateEditValid();
}
#spanadd
#spanend
@Override public void removeUpdate(DocumentEvent e) {
updateEditValid();
}
#spanadd
#spanend
private void updateEditValid() {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
ftf.setBackground(ftf.isEditValid() ? Color.WHITE : color);
}
});
}
});
return s;
#spanadd
}
#spanend
#spanadd
#spanend
#spanadd
private static DefaultFormatterFactory makeFFactory(SpinnerNumberModel m) {
#spanend
NumberFormat format = new DecimalFormat("####0");
NumberFormatter displayFormatter = new NumberFormatter(format);
NumberFormatter editFormatter = new NumberFormatter(format) {
@Override public Object stringToValue(String text) throws ParseException {
Long val = (Long)format.parse(text);
Long max = (Long)m.getMaximum();
Long min = (Long)m.getMinimum();
if(max.compareTo(val)<0 || min.compareTo(val)>0) {
throw new ParseException("xxx", 0);
@Override public Object stringToValue(String text)
throws ParseException {
try {
Long.parseLong(text);
} catch (NumberFormatException e) {
throw (ParseException) new ParseException(
ex.getMessage(), 0).initCause(ex);
}
return val;
Object o = format.parse(text);
if (o instanceof Long) {
Long val = (Long) format.parse(text);
Long max = (Long) m.getMaximum();
Long min = (Long) m.getMinimum();
if (max.compareTo(val) < 0 || min.compareTo(val) > 0) {
throw new ParseException("out of bounds", 0);
}
return val;
}
throw new ParseException("not Long", 0);
}
};
editFormatter.setAllowsInvalid(false);
//editFormatter.setCommitsOnValidEdit(true);
// editFormatter.setAllowsInvalid(false);
// editFormatter.setCommitsOnValidEdit(true);
editFormatter.setValueClass(Long.class);
return new DefaultFormatterFactory(displayFormatter, displayFormatter, editFormatter);
return new DefaultFormatterFactory(
displayFormatter, displayFormatter, editFormatter);
}
解説
上記のサンプルでは、DefaultFormatter#setAllowsInvalid(false) などを設定した DefaultFormatterFactory を作成して、JSpinnerから取得したJFormattedTextFieldにsetFormatterFactoryで追加しています。- プリミティブ型
long
を使用してnew SpinnerNumberModel(10L, 0L, 99_999L, 1L)
のようにSpinnerNumberModel
を作成するとClassCastException
が発生するようになった?
- 上
- SpinnerNumberModel を設定した通常のJSpinner
- 別コンポーネントにフォーカスが移動するときに、値が有効か無効かを判断
- 下
- SpinnerNumberModel を設定し、数値以外の無効な文字入力ができないようにしたJSpinner
java.lang.ClassCastException: class java.lang.Double cannot be cast to class java.lang.Long (java.lang.Double and java.lang.Long are in module java.base of loader 'bootstrap') at example.MainPanel$2.stringToValue(MainPanel.java:80) at java.desktop/javax.swing.JFormattedTextField.commitEdit(JFormattedTextField.java:563)
- SpinnerNumberModel を設定し、数値以外の無効な文字入力ができないようにしたJSpinner
参考リンク
- JTextFieldの入力を数値に制限する
-
Long
型のオブジェクトを使用するよう修正
コメント
#spanend
#spanadd
private static SpinnerNumberModel makeSpinnerNumberModel() {
#spanend
Long value = 10L;
Long minimum = 0L;
Long maximum = 99_999L;
Long stepSize = 1L;
return new SpinnerNumberModel(value, minimum, maximum, stepSize);
#spanadd
}
#spanend
#spanadd