---
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: https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTQg6Td8tI/AAAAAAAAAfs/u5mXLfk3k64/s800/NumberFormatter.png
---
* Summary [#summary]
`JSpinner`から`JFormattedTextField`を取得し、これに無効な値の入力を許可しないように設定します。
#download(https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTQg6Td8tI/AAAAAAAAAfs/u5mXLfk3k64/s800/NumberFormatter.png)
* Source Code Examples [#sourcecode]
#code(link){{
JSpinner spinner = new JSpinner(makeSpinnerNumberModel());
JSpinner.DefaultEditor editor =
(JSpinner.DefaultEditor) spinner.getEditor();
JFormattedTextField.AbstractFormatter formatter =
editor.getTextField().getFormatter();
if (formatter instanceof DefaultFormatter) {
((DefaultFormatter) formatter).setAllowsInvalid(false);
}
}}
* Description [#explanation]
* Description [#description]
上記のサンプルでは、`DefaultFormatter#setAllowsInvalid(false)`などを設定した`DefaultFormatterFactory`を作成して、`JSpinner`から取得した`JFormattedTextField`に`setFormatterFactory(...)`メソッドで追加しています。
- 上
-- `SpinnerNumberModel`を設定した通常の`JSpinner`
-- 別コンポーネントにフォーカスが移動するときに値が有効か無効かを判断
- 中
-- `SpinnerNumberModel`を設定し数値以外の無効な文字入力ができないようにした`JSpinner`
- 下
-- `SpinnerNumberModel`を設定した通常の`JSpinner`
-- 別コンポーネントにフォーカスが移動するときに値が有効か無効かを判断
-- 無効な値の場合は背景色を変更
#code{{
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();
}
@Override public void insertUpdate(DocumentEvent e) {
updateEditValid();
}
@Override public void removeUpdate(DocumentEvent e) {
updateEditValid();
}
private void updateEditValid() {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
ftf.setBackground(ftf.isEditValid() ? Color.WHITE : color);
}
});
}
});
return s;
}
private static DefaultFormatterFactory makeFFactory(SpinnerNumberModel m) {
NumberFormat format = new DecimalFormat("####0");
NumberFormatter displayFormatter = new NumberFormatter(format);
NumberFormatter editFormatter = new NumberFormatter(format) {
@Override public Object stringToValue(String text)
throws ParseException {
try {
Long.parseLong(text);
} catch (NumberFormatException e) {
throw (ParseException) new ParseException(
ex.getMessage(), 0).initCause(ex);
}
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.setValueClass(Long.class);
return new DefaultFormatterFactory(
displayFormatter, displayFormatter, editFormatter);
}
}}
- プリミティブ型`long`を使用して`new SpinnerNumberModel(10L, 0L, 99_999L, 1L)`のように`SpinnerNumberModel`を作成すると`ClassCastException`が発生するようになった?
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)
- `Long`型のオブジェクトを使用するよう修正
#code{{
private static SpinnerNumberModel makeSpinnerNumberModel() {
Long value = 10L;
Long minimum = 0L;
Long maximum = 99_999L;
Long stepSize = 1L;
return new SpinnerNumberModel(value, minimum, maximum, stepSize);
}
}}
* Reference [#reference]
- [[JTextFieldの入力を数値に制限する>Swing/NumericTextField]]
- [[SpinnerNumberModelに上限値を超える値を入力>Swing/SpinnerNumberModel]]
- [https://bugs.openjdk.org/browse/JDK-6423494 Bug ID: 6423494 SpinnerNumberModel should use getMinimum and getMaximum instead of fields]
* Comment [#comment]
#comment
- 無効な値が入力されたときの背景色の変更を`DocumentListener`で行うように修正。 -- &user(aterai); &new{2011-09-27 (火) 21:52:05};
#comment