---
category: swing
folder: HoverEnlargedButtonSpinner
title: JSpinnerの増減ボタンを分離・拡大する
title-en: Separate and enlarge the increase/decrease buttons of JSpinner
tags: [JSpinner, JPopupMenu, JButton]
author: aterai
pubdate: 2026-01-12T05:45:28+09:00
description: JSpinnerにフォーカスが移動したらその増減ボタンをJSpinner本体からJPopupMenuに移動し、クリックが容易になるようボタンサイズを拡大します。
summary-jp: JSpinnerにフォーカスが移動したらその増減ボタンをJSpinner本体からJPopupMenuに移動し、クリックが容易になるようボタンサイズを拡大します。
summary-en: When the focus is moved to the JSpinner, the increase/decrease buttons are moved from the JSpinner body to the JPopupMenu, and the button size is enlarged to make them easier to click.
image: https://drive.google.com/uc?id=1ZkidPHHXbv5zbn5fGJdRBP312SrGIRvE
---
* Summary [#summary]
JSpinnerにフォーカスが移動したらその増減ボタンをJSpinner本体からJPopupMenuに移動し、クリックが容易になるようボタンサイズを拡大します。
// #en{{When the focus is moved to the JSpinner, the increase/decrease buttons are moved from the JSpinner body to the JPopupMenu, and the button size is enlarged to make them easier to click.}}
`JSpinner`にフォーカスが移動したらその増減ボタンを`JSpinner`本体から`JPopupMenu`に移動し、クリックが容易になるようボタンサイズを拡大します。
// #en{{When the focus is moved to the `JSpinner`, the increase/decrease buttons are moved from the `JSpinner` body to the `JPopupMenu`, and the button size is enlarged to make them easier to click.}}
#download(https://drive.google.com/uc?id=1ZkidPHHXbv5zbn5fGJdRBP312SrGIRvE)
* Source Code Examples [#sourcecode]
#code(link){{
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;
}
}
}}
* Description [#description]
- `JSpinner`の増減ボタンを、たとえばタッチパネルでの操作でもクリックし易くなるよう拡大表示する
- 増減ボタンのコピーを`JPopupMenu`に配置して`JSpinner`とは切り離して表示することで`JSpinner`本体の高さは変更せず、増減ボタンのサイズのみ拡大する
-- [[JSpinnerのArrowButtonのサイズを変更>Swing/SpinnerArrowButtonSize]]では`JSpinner`本体の高さ変更に連動して、増減ボタンの高さを拡大している
- コピーした増減ボタンのサイズは`BasicArrowButton#getPreferredSize()`をオーバーライドして推奨サイズの幅を`4`倍、高さを`2`倍に拡大している
-- `UIManager.getDimension("Spinner.arrowButtonSize")`でも増減ボタンのサイズは取得可能だが、`NimbusLookAndFeel`では`null`になってしまう
- 増減ボタンのコピー配置した`JPopupMenu`の表示位置は`JSpinner#getEditor()`で取得したエディタの右端と中央を基準にしている
-- `ArrowButton`を基準: `WindowsLookAndFeel`で増減ボタンの名前が設定されていないため増減ボタンを取得しづらい
-- `JTextField`を基準: `((JSpinner.DefaultEditor) JSpinner#getEditor())#getTextField()`で取得可能な`JTextField`を基準にすると`NimbusLookAndFeel`で増減ボタンとの間隔が取得しづらい
- コピーした増減ボタンには、`BasicSpinnerUI`の`ArrowButtonHandler`を参考に長押しでクリックを自動繰り返しするリスナーを追加
-- `JSpinner.DateEditor`のキャレット位置による日時の増減機能は省略している
* Reference [#reference]
- [https://learn.microsoft.com/en-us/windows/apps/develop/ui/controls/number-box Number box - Windows apps | Microsoft Learn]
- [[JSpinnerのArrowButtonのサイズを変更>Swing/SpinnerArrowButtonSize]]
* Comment [#comment]
#comment
#comment