Swing/NumberFormatter の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/NumberFormatter へ行く。
- Swing/NumberFormatter の差分を削除
--- 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] `JSpinner`から`JFormattedTextField`を取得し、これに無効な値の入力を許可しないように設定します。 #download(https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTQg6Td8tI/AAAAAAAAAfs/u5mXLfk3k64/s800/NumberFormatter.png) * サンプルコード [#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); } }} * 解説 [#explanation] 上記のサンプルでは、`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(final SpinnerNumberModel m) { 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); 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] - [[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 - 無効な値が入力されたときの背景色の変更を`DocumentListener`で行うように修正。 -- &user(aterai); &new{2011-09-27 (火) 21:52:05}; #comment