Summary

JSpinnerに表示する数値を0.5単位で切り捨て、または四捨五入二捨三入・七捨八入するよう設定します。

Source Code Examples

private static DefaultFormatter makeDownFormatter() {
  return new DefaultFormatter() {
    @Override public Object stringToValue(String text) {
      return roundToDown(new BigDecimal(text)).doubleValue();
   }

   @Override public String valueToString(Object value) {
      return roundToDown(BigDecimal.valueOf((Double) value)).toString();
    }
  };
}

private static BigDecimal roundToDown(BigDecimal value) {
  return value.multiply(BigDecimal.valueOf(2))
      .setScale(0, RoundingMode.DOWN)
      .multiply(BigDecimal.valueOf(.5));
}
View in GitHub: Java, Kotlin

Explanation

  • Default, stepSize: 0.5
    • デフォルトのSpinnerNumberModelにステップサイズを0.5として使用
    • 矢印ボタンでJSpinnerの数値を変更すると0.5単位で増減するが、たとえば直接8.85を入力しても0.5単位の端数処理などは適用されない
  • Override SpinnerNumberModel
    • SpinnerNumberModel#setValue(...)メソッドをオーバーライドして値を丸め幅0.5単位で切り捨て
    • コンストラクタで初回の現在値を設定する場合はSpinnerNumberModel#setValue(...)が使用されないので、super(roundDownToHalf(value), min, max, step);のように切り捨てを実行している
      class RoundToHalfSpinnerModel extends SpinnerNumberModel {
        protected RoundToHalfSpinnerModel(
            double value, double min, double max, double step) {
          super(roundDownToHalf(value), min, max, step);
        }
      
        @Override public void setValue(Object value) {
          if (value instanceof Double) {
            Double v = roundDownToHalf((Double) value);
            if (!v.equals(getValue())) {
              super.setValue(v);
              fireStateChanged();
            }
          } else {
            throw new IllegalArgumentException("illegal value");
          }
        }
      
        private static double roundDownToHalf(Double value) {
          return BigDecimal.valueOf(value)
              .multiply(BigDecimal.valueOf(2))
              .setScale(0, RoundingMode.DOWN)
              .multiply(BigDecimal.valueOf(.5))
              .doubleValue();
        }
      }
      
  • Round down to half Formatter
    • JSpinner.DefaultEditorからJFormattedTextFieldを取得して、0.5単位で切り捨てを実行するDefaultFormatterFactoryを設定
    • 0.5単位の切り捨ては、BigDecimalの値を2倍したあとBigDecimal#setScale(0, RoundingMode.DOWN)で小数点以下を切り捨てし、0.5倍することで実行している
  • Round to half Formatter
    • JSpinner.DefaultEditorからJFormattedTextFieldを取得して、二捨三入・七捨八入(丸め幅0.5単位の五捨六入?)を実行するDefaultFormatterFactoryを設定
    • 0.5単位の二捨三入・七捨八入は、BigDecimalの値を2倍したあとBigDecimal#setScale(0, RoundingMode.HALF_UP)で小数点以下を四捨五入し、0.5倍することで実行している
    • スウェディッシュ・ラウンディング - Wikipedia
      private static BigDecimal roundToUp(BigDecimal value) {
        return value.multiply(BigDecimal.valueOf(2))
            .setScale(0, RoundingMode.HALF_UP)
            .multiply(BigDecimal.valueOf(.5));
      }
      

Reference

Comment