• title: JSpinnerでLocalDateTimeを使用する tags: [JSpinner, SpinnerModel, LocalDateTime] author: aterai pubdate: 2015-02-02T00:12:04+09:00 description: DateやCalendarなどを使用するSpinnerDateModelの代わりに、JDK 8で導入されたLocalDateTimeなどを使用するSpinnerModelを作成して、JSpinnerで日付を選択します。

概要

DateCalendarなどを使用するSpinnerDateModelの代わりに、JDK 8で導入されたLocalDateTimeなどを使用するSpinnerModelを作成して、JSpinnerで日付を選択します。

サンプルコード

class SpinnerLocalDateTimeModel extends AbstractSpinnerModel {
  private Comparable<ChronoLocalDateTime<?>> start, end;
  private LocalDateTime value;
  private TemporalUnit temporalUnit;

  public SpinnerLocalDateTimeModel(
      LocalDateTime value, Comparable<ChronoLocalDateTime<?>> start,
      Comparable<ChronoLocalDateTime<?>> end, TemporalUnit temporalUnit) {
    super();
    if (value == null) {
      throw new IllegalArgumentException("value is null");
    }
    if (!(start == null || start.compareTo(value) <= 0)
        && (end == null || end.compareTo(value) >= 0)) {
      throw new IllegalArgumentException("(start <= value <= end) is false");
    }
    this.value = value;
    this.start = start;
    this.end = end;
    this.temporalUnit = temporalUnit;
  }

  public void setStart(Comparable<ChronoLocalDateTime<?>> start) {
    if (start == null ? this.start != null : !start.equals(this.start)) {
      this.start = start;
      fireStateChanged();
    }
  }

  public Comparable<ChronoLocalDateTime<?>> getStart() {
    return start;
  }

  public void setEnd(Comparable<ChronoLocalDateTime<?>> end) {
    if (end == null ? this.end != null : !end.equals(this.end)) {
      this.end = end;
      fireStateChanged();
    }
  }

  public Comparable<ChronoLocalDateTime<?>> getEnd() {
    return end;
  }

  public void setTemporalUnit(TemporalUnit temporalUnit) {
    if (temporalUnit != this.temporalUnit) {
      this.temporalUnit = temporalUnit;
      fireStateChanged();
    }
  }

  public TemporalUnit getTemporalUnit() {
    return temporalUnit;
  }

  @Override public Object getNextValue() {
    //Calendar cal = Calendar.getInstance();
    //cal.setTime(value.getTime());
    //cal.add(calendarField, 1);
    //Date next = cal.getTime();
    LocalDateTime next = value.plus(1, temporalUnit);
    return end == null || end.compareTo(next) >= 0 ? next : null;
  }

  @Override public Object getPreviousValue() {
    //Calendar cal = Calendar.getInstance();
    //cal.setTime(value.getTime());
    //cal.add(calendarField, -1);
    //Date prev = cal.getTime();
    LocalDateTime prev = value.minus(1, temporalUnit);
    return start == null || start.compareTo(prev) <= 0 ? prev : null;
  }

  public LocalDateTime getLocalDateTime() {
    return value;
  }

  @Override public Object getValue() {
    return value;
  }

  @Override public void setValue(Object value) {
    if (!(value instanceof LocalDateTime)) {
      throw new IllegalArgumentException("illegal value");
    }
    if (!value.equals(this.value)) {
      this.value = (LocalDateTime) value;
      fireStateChanged();
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • 上: SpinnerDateModel
    • Calendarなどを使用して開始日、終了日を生成し、SpinnerDateModelを作成して、JSpinnerに設定
      Calendar cal = Calendar.getInstance();
      cal.clear(Calendar.MILLISECOND);
      cal.clear(Calendar.SECOND);
      cal.clear(Calendar.MINUTE);
      cal.set(Calendar.HOUR_OF_DAY, 0);
      Date date = cal.getTime();
      cal.add(Calendar.DATE, -2);
      Date start = cal.getTime();
      cal.add(Calendar.DATE, 9);
      Date end = cal.getTime();
      JSpinner spinner1 = new JSpinner(new SpinnerDateModel(
          date, start, end, Calendar.DAY_OF_MONTH));
      
    • 参考: JSpinnerで日付を設定
  • 下: SpinnerLocalDateTimeModel
    • 内部で、Dateではなく、LocalDateTimeを使用するSpinnerLocalDateTimeModel(AbstractSpinnerModelを継承)を作成
      LocalDateTime d = LocalDateTime.now();
      LocalDateTime s = d.minus(2, ChronoUnit.DAYS);
      LocalDateTime e = d.plus(7, ChronoUnit.DAYS);
      JSpinner spinner2 = new JSpinner(new SpinnerLocalDateTimeModel(
          d, s, e, ChronoUnit.DAYS));
      
    • スピナーエディタも、以下のようなLocalDateTimeを扱うものに変更
      class LocalDateTimeEditor extends JSpinner.DefaultEditor {
        private final DateTimeFormatter dateTimeFormatter;
      
        public LocalDateTimeEditor(final JSpinner spinner, String dateFormatPattern) {
          super(spinner);
          if (!(spinner.getModel() instanceof SpinnerLocalDateTimeModel)) {
            throw new IllegalArgumentException("model not a SpinnerLocalDateTimeModel");
          }
          dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormatPattern);
          final SpinnerLocalDateTimeModel model = (SpinnerLocalDateTimeModel) spinner.getModel();
      
          EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
              DefaultFormatter formatter = new InternationalFormatter(dateTimeFormatter.toFormat()) {
                @Override public String valueToString(Object value) throws ParseException {
                  //System.out.println(value.getClass().getName());
                  if (value instanceof LocalDateTime) {
                    return ((LocalDateTime) value).format(dateTimeFormatter);
                  } else {
                    return "";
                  }
                }
                @Override public Object stringToValue(String text) throws ParseException {
                  //System.out.println("stringToValue:" + text);
                  try {
                    return LocalDate.parse(text, dateTimeFormatter).atStartOfDay();
                  } catch (Exception e) {
                    // PENDING: e.printStackTrace();
                  }
                  return text;
                }
              };
              formatter.setValueClass(LocalDateTime.class);
              DefaultFormatterFactory factory = new DefaultFormatterFactory(formatter);
              JFormattedTextField ftf = (JFormattedTextField) getTextField();
      
              try {
                String maxString = formatter.valueToString(model.getStart());
                String minString = formatter.valueToString(model.getEnd());
                ftf.setColumns(Math.max(maxString.length(), minString.length()));
              } catch (ParseException e) {
                // PENDING: hmuller
              }
              ftf.setHorizontalAlignment(JTextField.LEFT);
              ftf.setEditable(true);
              ftf.setFormatterFactory(factory);
            }
          });
        }
      
        public SpinnerLocalDateTimeModel getModel() {
          return (SpinnerLocalDateTimeModel) getSpinner().getModel();
        }
      }
      

参考リンク

コメント