• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JComboBoxのドロップダウンリストで右クリックを無効化
#navi(../)
RIGHT:Posted by &author(aterai); at 2009-06-29
*JComboBoxのドロップダウンリストで右クリックを無効化 [#u3d32f35]
JComboBoxのドロップダウンリスト(ポップアップメニュー)で、マウスの右クリックを無効にします。
---
category: swing
folder: DisableRightClick
title: JComboBoxのドロップダウンリストで右クリックを無効化
tags: [JComboBox, BasicComboPopup, MouseListener, JList]
author: aterai
pubdate: 2009-06-29T10:14:32+09:00
description: JComboBoxのドロップダウンリスト(ポップアップメニュー)で、マウスの右クリックを無効にします。
image: https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTLKTBLgQI/AAAAAAAAAXI/mV-Gw1hPSYU/s800/DisableRightClick.png
hreflang:
    href: https://java-swing-tips.blogspot.com/2009/06/disable-right-click-in-jcombobox.html
    lang: en
---
* 概要 [#summary]
`JComboBox`のドロップダウンリスト(ポップアップメニュー)で、マウスの右クリックを無効にします。

-&jnlp;
-&jar;
-&zip;
#download(https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTLKTBLgQI/AAAAAAAAAXI/mV-Gw1hPSYU/s800/DisableRightClick.png)

//#screenshot
#ref(http://lh5.ggpht.com/_9Z4BYR88imo/TQTLKTBLgQI/AAAAAAAAAXI/mV-Gw1hPSYU/s800/DisableRightClick.png)
* サンプルコード [#sourcecode]
#code(link){{
class BasicComboPopup2 extends BasicComboPopup {
  private transient Handler2 handler2;

**サンプルコード [#re92d6d4]
#code{{
class BasicComboPopup2 extends BasicComboPopup {
  private Handler2 handler2;
  public BasicComboPopup2(JComboBox combo) {
    super(combo);
  }

  @Override public void uninstallingUI() {
    super.uninstallingUI();
    handler2 = null;
  }
  public BasicComboPopup2(JComboBox combo) {
    super(combo);
  }

  @Override protected MouseListener createListMouseListener() {
    if(handler2==null) handler2 = new Handler2();
    if (handler2 == null) {
      handler2 = new Handler2();
    }
    return handler2;
  }
  private class Handler2 implements MouseListener{
    @Override public void mouseEntered(MouseEvent e) {}
    @Override public void mouseExited(MouseEvent e)  {}
    @Override public void mouseClicked(MouseEvent e) {}
    @Override public void mousePressed(MouseEvent e) {}

  private class Handler2 extends MouseAdapter {
    @Override public void mouseReleased(MouseEvent e) {
      if(e.getSource() == list) {
        if(list.getModel().getSize() > 0) {
      if (e.getSource().equals(list)) {
        if (list.getModel().getSize() > 0) {
          // <ins>
          if(!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) return;
          if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) {
            return;
          }
          // </ins>
          // JList mouse listener
          if(comboBox.getSelectedIndex() == list.getSelectedIndex()) {
          if (comboBox.getSelectedIndex() == list.getSelectedIndex()) {
            comboBox.getEditor().setItem(list.getSelectedValue());
          }
          comboBox.setSelectedIndex(list.getSelectedIndex());
        }
        comboBox.setPopupVisible(false);
        // workaround for cancelling an edited item (bug 4530953)
        if(comboBox.isEditable() && comboBox.getEditor() != null) {
        if (comboBox.isEditable() && comboBox.getEditor() != null) {
          comboBox.configureEditor(comboBox.getEditor(), comboBox.getSelectedItem());
        }
      }
    }
  }
}
}}

**解説 [#y202ff9d]
上記のサンプルでは、ComboBoxUI#createPopup()をオーバーライドして、ドロップダウンリストに設定するMouseListenerを入れ替えたBasicComboPopupを追加しています。
* 解説 [#explanation]
上記のサンプルでは、`ComboBoxUI#createPopup()`をオーバーライドして、ドロップダウンリストに設定する`MouseListener`を入れ替えた`BasicComboPopup`を追加しています。

#code{{
combo02.setUI(new BasicComboBoxUI() {
  @Override protected ComboPopup createPopup() {
    return new BasicComboPopup2( comboBox );
    return new BasicComboPopup2(comboBox);
  }
});
}}

元のMouseListenerは、JComboBox全体のHandlerになっていますが、必要なのはドロップダウンリスト関係のみなので、e.getSource() == listな部分だけ元のHandlerからコピーし、この中でif(!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) return;と右クリックを無視しています。
元の`MouseListener`は、`JComboBox`全体の`Handler`になっていますが、必要なのはドロップダウンリスト関係のみなので、`e.getSource() == list`な部分だけ元の`Handler`からコピーし、この中で`if(!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) return;`と右クリックを無視しています。

----
以下のような方法もあります。

#code{{
class BasicComboPopup3 extends BasicComboPopup {
  public BasicComboPopup3(JComboBox combo) {
    super(combo);
  }
  @SuppressWarnings("unchecked")
  @Override protected JList createList() {
    return new JList(comboBox.getModel()) {
      @Override public void processMouseEvent(MouseEvent e) {
        if(SwingUtilities.isRightMouseButton(e)) return;
        if(e.isControlDown()) {
          // Fix for 4234053. Filter out the Control Key from the list. 
        if (SwingUtilities.isRightMouseButton(e)) {
          return;
        }
        MouseEvent ev = e;
        if (e.isControlDown()) {
          // Fix for 4234053. Filter out the Control Key from the list.
          // ie., don't allow CTRL key deselection.
          e = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(), 
                     e.getModifiers() ^ InputEvent.CTRL_MASK,
                     e.getX(), e.getY(),
                     e.getXOnScreen(), e.getYOnScreen(),
                     e.getClickCount(),
                     e.isPopupTrigger(),
                     MouseEvent.NOBUTTON);
          Toolkit toolkit = Toolkit.getDefaultToolkit();
          ev = new MouseEvent(e.getComponent(), e.getID(), e.getWhen(),
                              //e.getModifiers() ^ InputEvent.CTRL_MASK,
                              e.getModifiers() ^ toolkit.getMenuShortcutKeyMask(),
                              e.getX(), e.getY(),
                              e.getXOnScreen(), e.getYOnScreen(),
                              e.getClickCount(),
                              e.isPopupTrigger(),
                              MouseEvent.NOBUTTON);
        }
        super.processMouseEvent(e);
        super.processMouseEvent(ev);
      }
    };
  }
}
}}

//**参考リンク
**コメント [#f7806cb9]
* 参考リンク [#reference]
- [https://bugs.openjdk.org/browse/JDK-4249731 JDK-4249731 JComboBox (Windows L&F), right mouse click selects in menu - Java Bug System]
-- 要望が矛盾しているとして却下されているが、もしかしたら「`Windows`環境の標準動作に合わせて、`WindowsLookAndFeel`の`JComboBox`では右クリックしてもドロップダウンリストを閉じないようにして欲しい」との意味だったのかもしれない
- [[JMenuとJMenuItemで右クリックによる選択を無効にする>Swing/DisableRightClickOnMenu]]
-- `JMenu`と`JMenuItem`も同様にマウス右クリックの無効化が可能

* コメント [#comment]
#comment
- ドロップダウンリストにスクロールバーが表示されていない場合、ホイールを回すとポップアップが閉じてしまうのも地味に困る…。[https://bugs.openjdk.org/browse/JDK-8033069 JDK-8033069 mouse wheel scroll closes combobox popup - Java Bug System] -- &user(aterai); &new{2012-04-24 (火) 18:28:39};

#code{{
// Test
class BasicComboPopup3 extends BasicComboPopup {
  public BasicComboPopup3(JComboBox combo) {
    super(combo);
  }

  @Override protected JScrollPane createScroller() {
    JScrollPane sp = new JScrollPane(list,
                     ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                     ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) {
      @Override protected void processEvent(AWTEvent e) {
        if (e instanceof MouseWheelEvent) {
          JScrollBar toScroll = getVerticalScrollBar();
          if (toScroll == null || !toScroll.isVisible()) {
            ((MouseWheelEvent) e).consume();
            return;
          }
        }
        super.processEvent(e);
      }
    };
    sp.setHorizontalScrollBar(null);
    return sp;
  }
// ...
}}

- 上記の方法では、ドロップダウンリスト内では閉じなくなるが、ドロップダウンリスト外でホイールを回転するとポップアップが閉じてしまう。`Toolkit.getDefaultToolkit().addAWTEventListener(...)`でもうまくいかない。 -- &user(aterai); &new{2012-04-24 (火) 20:07:13};
- [https://bugs.openjdk.org/browse/JDK-8033069 JDK-8033069 mouse wheel scroll closes combobox popup - Java Bug System]で、ホイール回転の方は修正され%%る予定(`Java 9`)%%、`JDK 8`にも[https://bugs.openjdk.org/browse/JDK-8078391 バックポート]された。 -- &user(aterai); &new{2015-05-07 (木) 15:59:53};

#comment