TITLE:JListをマウスクリックのみで複数選択する

Posted by at 2011-07-18

JListをマウスクリックのみで複数選択する

`JList`をアイテムをマウスクリックだけで複数選択できるように設定します。

  • &jnlp;
  • &jar;
  • &zip;
ListMouseSelection.png

サンプルコード

JList list = new JList(model) {
  private ClearSelectionListener listener;
  @Override public void setSelectionInterval(int anchor, int lead) {
    if(anchor==lead && lead>=0 && anchor>=0) {
      if(listener.isDragging) {
        addSelectionInterval(anchor, anchor);
      }else if(!listener.isInCellDragging) {
        if(isSelectedIndex(anchor)) {
          removeSelectionInterval(anchor, anchor);
        }else{
          addSelectionInterval(anchor, anchor);
        }
        listener.isInCellDragging = true;
      }
    }else{
      super.setSelectionInterval(anchor, lead);
    }
  }
};
View in GitHub: Java, Kotlin

解説

  • 左: `Default`
  • 中: `MouseEvent`
    • `JList#processMouseEvent, JList#processMouseMotionEvent`をオーバーライドして、常にCtrlキーが押されている状態にする
    • マウスでアイテムをドラッグしても選択状態は変わらない
    • `JListの空白部分をクリックした場合、アイテムの選択状態は変更せず(MouseEvent#consume())、フォーカスだけJList`に移動
    • 参考: Swing - JList where mouse click acts like ctrl-mouse click
JList list = new JList(model) {
  @Override protected void processMouseMotionEvent(MouseEvent e) {
    super.processMouseMotionEvent(convertMouseEvent(e));
  }
  @Override protected void processMouseEvent(MouseEvent e) {
    if(e.getID()==MouseEvent.MOUSE_PRESSED &&
       !getCellBounds(0, getModel().getSize()-1).contains(e.getPoint())) {
      e.consume();
      requestFocusInWindow();
    }else{
      super.processMouseEvent(convertMouseEvent(e));
    }
  }
  private MouseEvent convertMouseEvent(MouseEvent e) {
    //Swing - JList where mouse click acts like ctrl-mouse click
    //https://forums.oracle.com/thread/1351452
    return new MouseEvent(
      (Component) e.getSource(),
      e.getID(), e.getWhen(),
      //e.getModifiers() | InputEvent.CTRL_MASK,
      //select multiple objects in OS X: Command+click
      //pointed out by nsby
      e.getModifiers() | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(),
      e.getX(), e.getY(),
      e.getXOnScreen(), e.getYOnScreen(),
      e.getClickCount(),
      e.isPopupTrigger(),
      e.getButton());
  }
};
  • 右: `SelectionInterval`
    • `JList#setSelectionIntervalをオーバーライドして、ひとつのアイテムのセルを選択した場合は、JList#addSelectionIntervalJList#removeSelectionInterval`を使用するように変更
    • マウスでアイテムをドラッグすると、選択状態になる
    • ひとつのアイテムのセル内でのドラッグでは、選択状態を変更しない
    • 参考: Swing - Re: JList where mouse click acts like ctrl-mouse click
    • `JList`の空白部分をクリックした場合、アイテムの選択状態をすべてクリア(JListの選択を解除)

参考リンク

コメント

  • `OSX(snow leopard)では、MouseEvent`は複数選択が出来ません。キーボードを使っても(command+クリック)無理でした。 -- nsby
    • ご指摘ありがとうございます。`OSXでは「command+クリック」で複数選択でしたっけ? InputEvent.CTRL_MASK決め打ちではなく、Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()`に修正した方がいいのかもしれません(ソースなどを更新しましたが、正常に動作するかは確認していません…)。 -- aterai
  • `Web Startでもう一度実行してみましたが、やはり出来ませんでした。MouseEvent`で複数選択ha -- nsby
  • あ、変な所で切れてしまいました。すみません。あらためて、`MouseEvent`で複数選択出来るのは、Shift+クリックで選択した場合のみです。それ意外はダメでした。(Ctrl+クリックとかでもダメ) -- nsby
    • `Web Startのキャッシュは、…関係なさそうですね。src.zipをダウンロードしてJList#processMouseEvent(...)内で、System.out.println(e);したりsuper.processMouseEvent(convertMouseEvent(e));`だけにしてみるとどうなるでしょうか? -- aterai
  • `MouseEvent e`を出力してみました。ちゃんと処理してるように見えるんですが・・・
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() : 0x04 InputEvent.CTRL_MASK : 0x02
[ただのクリック]
java.awt.event.MouseEvent[MOUSE_PRESSED,(57,4),absolute(971,484),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,alignmentY
=0.0,border=,flags=50331944,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFactory$Sy
stemColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x10

java.awt.event.MouseEvent[MOUSE_RELEASED,(57,4),absolute(971,484),button=1,modifiers=Button1,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,alignmentY=0.0,border=,flags=5
0331944,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=39,
g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x10

java.awt.event.MouseEvent[MOUSE_CLICKED,(57,4),absolute(971,484),button=1,modifiers=Button1,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,alignmentY=0.0,border=,flags=50
331944,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=39,g
=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x10

[Cntl + クリック]
java.awt.event.MouseEvent[MOUSE_PRESSED,(57,40),absolute(971,520),button=1,modifiers=?+Button1,extModifiers=?+Button1,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,align
mentY=0.0,border=,flags=50332008,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFacto
ry$SystemColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x12

java.awt.event.MouseEvent[MOUSE_RELEASED,(57,40),absolute(971,520),button=1,modifiers=?+Button1,extModifiers=?,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,alignmentY=0
.0,border=,flags=50332008,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFactory$Syst
emColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x12

java.awt.event.MouseEvent[MOUSE_CLICKED,(57,40),absolute(971,520),button=1,modifiers=?+Button1,extModifiers=?,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,alignmentY=0.
0,border=,flags=50332008,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFactory$Syste
mColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x12

[Command + クリック]
java.awt.event.MouseEvent[MOUSE_PRESSED,(56,72),absolute(970,552),button=1,modifiers=?+Button1+Button3,extModifiers=?+Button1,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0
.0,alignmentY=0.0,border=,flags=50332008,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaIm
ageFactory$SystemColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x14

java.awt.event.MouseEvent[MOUSE_RELEASED,(56,72),absolute(970,552),button=1,modifiers=?+Button1+Button3,extModifiers=?,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,alig
nmentY=0.0,border=,flags=50332008,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFact
ory$SystemColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x14

java.awt.event.MouseEvent[MOUSE_CLICKED,(56,72),absolute(970,552),button=1,modifiers=?+Button1+Button3,extModifiers=?,clickCount=1] on example.MainPanel$1[,0,0,106x193,alignmentX=0.0,align
mentY=0.0,border=,flags=50332008,maximumSize=,minimumSize=,preferredSize=,fixedCellHeight=-1,fixedCellWidth=-1,horizontalScrollIncrement=-1,selectionBackground=com.apple.laf.AquaImageFacto
ry$SystemColorProxy[r=39,g=118,b=218],selectionForeground=com.apple.laf.AquaImageFactory$SystemColorProxy[r=255,g=255,b=255],visibleRowCount=8,layoutOrientation=0] e.getModifiers() : 0x14
  • ちなみに `e.getModifiers() | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(),e.getModifiers() | 0x01, #0x01`は Shiftとかに無理矢理するとクリックだけでShiftと同じ動作になるんですけどね・・・。もう意味が分かりません。 -- nsby
  • あら見づらくなりすみません。 -- nsby
  • ようするに、`convertMouseEvent内のe.getModifiers()0x02/0x04orしてもOSX`では無視されてるようです。なぜなんでしょう? -- nsby
    • ログ(勝手にすこし整形しました)どうもです。たしかにうまくいっているっぽいのに、不思議な感じですね。 `InputEvent.CTRL_DOWN_MASKInputEvent.CTRL_MASK`の違い? もうすこし調べてみます。 -- aterai
  • メモ: Tailoring Java Applications for Mac OS X -- aterai
  • ドラッグによる`JList`の複数選択は、JListのアイテムを範囲指定で選択を使用する方法もあります。 -- aterai