- PR -

JSpinnerへの直接入力時の動作。

投稿者投稿内容
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-05-21 15:28
引用:

taichiさんの書き込み (2004-05-21 13:31) より:
目的は、まずJSpinnerに対してSpinnerNumberModelを使用して制限をかけているのですが、Max/Minともにユーザーの設定で変化し、Stepは正確には54の逆数するようになっています。しかし、キーボード入力の際にMax/Minが機能せず、それで仕方なくgetValueをオーバーライドして制限をかけたんです。


キーボード入力に対しても、最大値/最小値のチェックはおこなわれますよ。
テキストの入力が範囲外の場合、Modelの値は変更されません。
テキストフィールドからフォーカスが外れれば、もとの値が表示されるはずです。
また、最大値/最小値のチェック以外のチェックを行いたい場合でも、JSpinner#setValue()ではなく、SpinnerNumberModel#setValue()をオーバーライドするほうが適切です。

引用:
そしてデバッグの環境でこのSpinnerの動作を見てみると、Spinnerのボタンを押した時はgetvalueのObjectはdoubleの値をもっているのですが、キーボードからの入力の時にはintになってしまっているのです。


これは、JSpinner#setValue()をオーバーライドした場合のみにおこると言う事でしょうか?
それならば、原因はオーバーライドしたsetValue()の中にあります。その内容がわからないことには何もアドバイスを差し上げられません。

引用:
キーボードからの入力の時に制限などの設定をするのには、NumberModelではなく別の設定が必要なのでしょうか?


これは、どのような制限をしたいかによります。
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-05-21 15:28
# 2重になってしまったので削除

[ メッセージ編集済み 編集者: Wata 編集日時 2004-05-21 15:29 ]
taichi
会議室デビュー日: 2004/01/28
投稿数: 14
投稿日時: 2004-05-25 14:40
Wataさん。いっきゅうさん。ありがとうございます。
いっきゅうさんの言う通り、素直に書くと直接入力からでも小数を入力することができました。
この入力できない問題はcommitEditをオーバーライドしたせいのようです。getValueはオーバーライドしてもしなくても関係ありませんでした。でも、commitEditをオーバーライドしないと前回の質問でWataさんに教えて頂いた、丸めの誤差による表示桁数の問題が解決しなくなってしまいます。
おそらく私のプログラムの中のSpinnerCommitEditの部分の書き方がどこか適切でないのでしょう。もう一度考えなおしてみます。

>Wataさん
getValueをオーバーライドした理由の補足で、Wataさんの言う通り最大最小のチェックは機能しているのですが、これでは入力された値がはじかれてしまいます。私としてはもし最大値以上の値が入力された時は、最大値を表示するようにしたかったのです。(最小値も同様に最小値以下の場合、最小値を表示させる。)
これはSpinnerNumberModelで行うように変更してみます。
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-05-25 17:51
引用:

>Wataさん
getValueをオーバーライドした理由の補足で、Wataさんの言う通り最大最小のチェックは機能しているのですが、これでは入力された値がはじかれてしまいます。私としてはもし最大値以上の値が入力された時は、最大値を表示するようにしたかったのです。(最小値も同様に最小値以下の場合、最小値を表示させる。)
これはSpinnerNumberModelで行うように変更してみます。


これについてですが、SpinnerNumberModelをいじっても無理かもしれません。
(範囲外の場合、SpinnerNumberModel#setValue()が呼ばれないので)
結構難しそうな気がしたのでやってみました。

コード:
import java.awt.BorderLayout;
import java.text.*;
import javax.swing.*;
import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.text.*;

public class Spinner extends JFrame {
   /** メイン */
   public static void main(String[] args) {

      Spinner f = new Spinner("Spinner");

      f.pack();
      f.setLocationRelativeTo(null);

      f.setVisible(true);
   }

   /** コンストラクタ */
   public Spinner(String title) {
      super(title);

      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      getContentPane().add(getSpinner());
      getContentPane().add(new JButton("hoge"), BorderLayout.SOUTH);
   }
   /** スピナー生成 */
   private JSpinner getSpinner() {
      final SpinnerNumberModel model =
         new SpinnerNumberModel(0.000000, -50.000000, 50.000000, 0.023023);
      final JSpinner spinner = new JSpinner(model);

      spinner.setEditor(new SpinnerEditor2(spinner, "0.000"));

      return spinner;
   }
   
   /** 自作NumberEditorFormatterクラス */
   private static class MyNumberEditorFormatter
      extends InternationalFormatter {
      private final SpinnerNumberModel model;

      MyNumberEditorFormatter(
         SpinnerNumberModel model,
         NumberFormat format) {
         super(format);
         this.model = model;
         setValueClass(model.getValue().getClass());
      }

      public Comparable getMaximum() {
         return model.getMaximum();
      }
      public Comparable getMinimum() {
         return model.getMinimum();
      }
      public void setMaximum(Comparable max) {
         model.setMaximum(max);
      }
      public void setMinimum(Comparable min) {
         model.setMinimum(min);
      }

      /**
       * 文字列→値変換メソッドをオーバーライドする。
       * 範囲外の時は、値を最大値、または最小値に修正する。
       * @see javax.swing.text.InternationalFormatter#stringToValue(java.lang.String)
       */
      public Object stringToValue(String text) throws ParseException {
         try {
            return super.stringToValue(text);
         }
         catch (ParseException e) {
            // 範囲外の場合、ParseExceptionが投げられるのでキャッチする。
            
            Object object = getFormat().parseObject(text);

            Double d;
            if (object instanceof Double) {
               d = (Double)object;
            }
            else if (object instanceof Number) {
               d = new Double(((Number)object).doubleValue());
            }
            else {
               throw e;
            }

            if (getMaximum().compareTo(d) < 0) {
               // 最大を超えている場合は、最大値を返す。
               return getMaximum();
            }
            else if (getMinimum().compareTo(d) > 0) {
               // 最小に満たない場合は、最小値を返す。
               return getMinimum();
            }
            else {
               throw e;
            }
         }
      }
   }

   private static class SpinnerEditor2 extends JSpinner.NumberEditor {
      /**
       * コンストラクタ
       * @param spinner
       * @param decimalFormatPattern
       */
      public SpinnerEditor2(JSpinner spinner, String decimalFormatPattern) {
         super(spinner, decimalFormatPattern);

         // Formatterを自作のものに変更する。
         MyNumberEditorFormatter formatter =
            new MyNumberEditorFormatter(
               (SpinnerNumberModel)spinner.getModel(),
               new DecimalFormat(decimalFormatPattern));
               
         DefaultFormatterFactory factory =
            new DefaultFormatterFactory(formatter);
         
         getTextField().setFormatterFactory(factory);
      }

      /* (non-Javadoc) override
       * @see javax.swing.JSpinner.DefaultEditor#commitEdit()
       */
      public void commitEdit() throws ParseException {
         Object old = getModel().getValue();
         String newStr = getTextField().getText();

         try {
            AbstractFormatter formatter = getTextField().getFormatter();
            String oldStr = formatter.valueToString(old);

            // 頭の部分が変わってなかったら、変更しない
            if (newStr.startsWith(oldStr)) {
               return;
            }
         }
         catch (ParseException e) {
            // 起こらないハズ 
            e.printStackTrace();
         }
         // 変更を確定させる。
         super.commitEdit();
      }
   }
}



実際、かなり悩みましたが、これで目的の動作になったと思います。
参考にしてみてください。なお、結構荒っぽいコーディングをしているので、
コピペではなく、なるべく理解して使うようにお願いします。
taichi
会議室デビュー日: 2004/01/28
投稿数: 14
投稿日時: 2004-05-28 18:00
Wataさん、ありがとうございます。
これを利用して思うように動作させることができました。
やはりまだまだ自分のプロミング力のなさを感じます。
これからも精進していきます。
ほんとにありがとうございました。m(_ _)m

スキルアップ/キャリアアップ(JOB@IT)