Summary

JSpinnerにフォーカスが移動したらその増減ボタンをJSpinner本体からJPopupMenuに移動し、クリックが容易になるようボタンサイズを拡大します。

Source Code Examples

class EnlargedButtonSpinner extends JSpinner {
  private transient MouseAdapter listener;

  protected EnlargedButtonSpinner(SpinnerModel model) {
    super(model);
  }

  @Override public void updateUI() {
    JTextField field = ((JSpinner.DefaultEditor) getEditor()).getTextField();
    field.removeMouseListener(listener);
    super.updateUI();
    listener = new ArrowButtonEnlargeListener();
    field.addMouseListener(listener);
  }
}

class ArrowButtonEnlargeListener extends MouseAdapter {
  private final JPopupMenu popup = new JPopupMenu();

  @Override public void mousePressed(MouseEvent e) {
    Component c = SwingUtilities.getAncestorOfClass(
        JSpinner.class, e.getComponent());
    if (SwingUtilities.isLeftMouseButton(e) && c instanceof JSpinner) {
      JSpinner spinner = (JSpinner) c;
      JButton bigNextBtn = makeArrowButton(spinner, true);
      JButton bigPrevBtn = makeArrowButton(spinner, false);
      popup.setLayout(new GridLayout(2, 1));
      popup.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
      popup.setFocusable(false);
      popup.removeAll();
      popup.add(bigNextBtn);
      popup.add(bigPrevBtn);
      popup.pack();
      JComponent editor = spinner.getEditor();
      Rectangle r = SwingUtilities.calculateInnerArea(editor, null);
      int px = (int) r.getMaxX();
      int py = (int) r.getCenterY() - bigNextBtn.getPreferredSize().height;
      popup.show(editor, px, py);
    }
  }

  private static JButton makeArrowButton(JSpinner spinner, boolean isNext) {
    int direction = isNext ? SwingConstants.NORTH : SwingConstants.SOUTH;
    JButton arrowButton = new BasicArrowButton(direction) {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.width *= 4;
        d.height *= 2;
        return d;
      }
    };
    String name = isNext ? "increment" : "decrement";
    ArrowButtonHandler handler = new ArrowButtonHandler(spinner, name, isNext);
    arrowButton.addActionListener(handler);
    arrowButton.addMouseListener(handler);
    return arrowButton;
  }
}
View in GitHub: Java, Kotlin

Description

  • JSpinnerの増減ボタンを、たとえばタッチパネルでの操作でもクリックし易くなるよう拡大表示する
  • 増減ボタンのコピーをJPopupMenuに配置してJSpinnerとは切り離して表示することでJSpinner本体の高さは変更せず、増減ボタンのサイズのみ拡大する
  • コピーした増減ボタンのサイズはBasicArrowButton#getPreferredSize()をオーバーライドして推奨サイズの幅を4倍、高さを2倍に拡大している
    • UIManager.getDimension("Spinner.arrowButtonSize")でも増減ボタンのサイズは取得可能だが、NimbusLookAndFeelではnullになってしまう
  • 増減ボタンのコピー配置したJPopupMenuの表示位置はJSpinner#getEditor()で取得したエディタの右端と中央を基準にしている
    • ArrowButtonを基準: WindowsLookAndFeelで増減ボタンの名前が設定されていないため増減ボタンを取得しづらい
    • JTextFieldを基準: *1#getTextField()で取得可能なJTextFieldを基準にするとNimbusLookAndFeelで増減ボタンとの間隔が取得しづらい
  • コピーした増減ボタンには、BasicSpinnerUIArrowButtonHandlerを参考に長押しでクリックを自動繰り返しするリスナーを追加
    • JSpinner.DateEditorのキャレット位置による日時の増減機能は省略している

Reference

Comment