• category: swing folder: SpinnerMenuItem title: JPopupMenuのMenuItemとしてJSpinnerを配置する tags: [JSpinner, JMenuItem, JPopupMenu, JSlider, LayoutManager] author: aterai pubdate: 2025-01-27T07:43:46+09:00 description: JPopupMenuのMenuItemとしてMenuElementを実装しないJSpinnerやJSliderなどのコンポーネントを使用します。 image: https://drive.google.com/uc?id=1QqtQjPQ5KaFOGQr-RBfKkE-gkwyRmg8r

Summary

JPopupMenuMenuItemとしてMenuElementを実装しないJSpinnerJSliderなどのコンポーネントを使用します。

Source Code Examples

private static Component makeSpinnerMenuItem(String title, Component c) {
  JMenuItem item = new JMenuItem() {
    @Override public void updateUI() {
      super.updateUI();
      setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
      setEnabled(false);
      setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
    }

    @Override public Dimension getPreferredSize() {
      Dimension d = super.getPreferredSize();
      d.height = Math.max(d.height, c.getPreferredSize().height);
      return d;
    }
  };
  item.add(new JLabel(title));
  item.add(c);
  return item;
}

private static JMenu makeSpinnerMenu() {
  SpinnerNumberModel model1 = new SpinnerNumberModel(100, 10, 300, 10);
  SpinnerNumberModel model2 = new SpinnerNumberModel(150, 10, 300, 10);
  JMenu menu = new JMenu("JSpinner");
  menu.add(makeMenuBox("L: ", makeSpinner(model1)));
  menu.add(makeMenuBox("R: ", makeSpinner(model2)));
  menu.add(new JSeparator());
  menu.add(makeSpinnerMenuItem("Left: ", makeSpinner(model1)));
  menu.add(makeSpinnerMenuItem("Right: ", makeSpinner(model2)));
  menu.addSeparator();
  menu.add("JMenuItem1");
  menu.add("JMenuItem2");
  menu.add(Box.createHorizontalStrut(160));
  return menu;
}

private static JSpinner makeSpinner(SpinnerModel model) {
  JSpinner spinner = new JSpinner(model);
  ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(8);
  spinner.addMouseWheelListener(e -> {
    JSpinner s = (JSpinner) e.getComponent();
    SpinnerModel o = s.getModel();
    if (s.isEnabled() && o instanceof SpinnerNumberModel) {
      SpinnerNumberModel m = (SpinnerNumberModel) o;
      m.setValue(m.getNumber().intValue() - e.getWheelRotation());
    }
    e.consume();
  });
  return spinner;
}
View in GitHub: Java, Kotlin

Explanation

  • JSpinnerメニュー上: Box.createHorizontalBox()にタイトル表示用のJLabelJSpinnerを配置してJMenu#add(...)JPopupMenuに配置
    • MenuElementを実装しないコンポーネントなのでキー入力などでのメニュー選択などは不可だが、JSpinner自体のマウス入力での操作やTabキー入力によるフォーカス移動は可能
  • JSpinnerメニュー下: 無効化したJMenuItemのタイトルを空、かつ右寄せのFlowLayoutを設定し、別途タイトル表示用のJLabelJSpinnerを配置してJMenu#add(...)JPopupMenuに配置
    • MenuElementを実装するJMenuItemなのでキー入力などでのメニュー選択が可能で、かつJSpinner自体のマウス入力での操作やTabキー入力によるフォーカス移動も可能
    • 無効化したJMenuItemの選択状態表示はDisabledなJMenuItemのハイライトをテストのようにLookAndFeelに依存する
    • JSpinnerに追加したMouseWheelListenerでホイール回転による値の変更も可能
    • 無効化したJMenuItemでクリックしてもJPopupMenuを閉じないよう設定するのではなく、選択アイコンを非表示化したJCheckBoxMenuItemputClientProperty("CheckBoxMenuItem.doNotCloseOnMouseClick", true)を設定して使用する方法もJava 9以降では可能
  • JSliderメニュー

Reference

Comment