概要

JTableで、日付を表示する列のセルエディタをJSpinnerにします。

サンプルコード

class SpinnerCellEditor extends JSpinner implements TableCellEditor {
  private final JSpinner.DateEditor editor;
  public SpinnerCellEditor() {
    super(new SpinnerDateModel());
    setEditor(editor = new JSpinner.DateEditor(this, "yyyy/MM/dd"));
    setArrowButtonEnabled(false);
    editor.getTextField().setHorizontalAlignment(JFormattedTextField.LEFT);

    addFocusListener(new FocusAdapter() {
      @Override public void focusGained(FocusEvent e) {
        // System.out.println("spinner");
        editor.getTextField().requestFocusInWindow();
      }
    });
    editor.getTextField().addFocusListener(new FocusAdapter() {
      @Override public void focusLost(FocusEvent e) {
        setArrowButtonEnabled(false);
      }

      @Override public void focusGained(FocusEvent e) {
        // System.out.println("getTextField");
        setArrowButtonEnabled(true);
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            editor.getTextField().setCaretPosition(8);
            editor.getTextField().setSelectionStart(8);
            editor.getTextField().setSelectionEnd(10);
          }
        });
      }
    });
    setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  }

  private void setArrowButtonEnabled(boolean flag) {
    for (Component c : getComponents()) {
      if (c instanceof JButton) {
        ((JButton) c).setEnabled(flag);
      }
    }
  }

  @Override public Component getTableCellEditorComponent(JTable table,
      Object value, boolean isSelected, int row, int column) {
    setValue(value);
    return this;
  }

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

  // Copied from AbstractCellEditor
  // protected EventListenerList listenerList = new EventListenerList();
  transient protected ChangeEvent changeEvent = null;

  @Override public boolean stopCellEditing() {
    try {
      commitEdit();
    } catch (Exception pe) {
      Toolkit.getDefaultToolkit().beep();
      return false;
    }
    fireEditingStopped();
    return true;
  }
  // ...
View in GitHub: Java, Kotlin

解説

TableModel#getColumnClass(int)で第2列目が日付(Date.class)を返すように設定し、JTable#setDefaultEditor(Class,CellEditor)メソッドで上記のセルエディタを関連付けています。

table.setDefaultEditor(Date.class, new SpinnerCellEditor());
table.setSurrendersFocusOnKeystroke(true);
  • 日付用のセルエディタ(SpinnerCellEditor):
    • SpinnerEditorで左寄せ
      • デフォルトのセルレンダラーと合わせるため
      • 1.6.0_07, 1.6.0_06, 1.5.0_16などで、JSpinner(WindowsLookAndFeel)の文字サイズ、余白が微妙に異なる?
    • ダブルクリックで編集開始
    • 編集開始時のキャレットは先頭の「年(yyyy)」ではなく「日(dd)」上にあり、この「日(dd)」が選択状態になるよう設定
      • 編集開始直後にUpDownキーで「日(dd)」の値を変更可能にするために必要
    • 編集開始時、スピナエディタにフォーカスが無い場合は、スピナボタンはクリック不可に設定
      • 編集開始と同時に、スピナボタンが押されて日付が変更されるのを防止するため

参考リンク

コメント