TITLE:JListのアイテムを範囲指定で選択

JListのアイテムを範囲指定で選択

編集者:Terai Atsuhiro~

作成日:2006-08-14
更新日:2022-08-17 (水) 14:32:17
  • category: swing folder: RubberBanding title: JListのアイテムを範囲指定で選択 tags: [JList, MouseListener, MouseMotionListener] author: aterai pubdate: 2006-08-14T01:35:31+09:00 description: JListのアイテムをラバーバンドで範囲指定して選択します。 image: https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTSd-lu2aI/AAAAAAAAAi0/AQTsBqR1OUc/s800/RubberBanding.png hreflang:
       href: https://java-swing-tips.blogspot.com/2008/10/using-rubber-band-selection-in-jlist.html
       lang: en

概要

JListのアイテムをラバーバンドで範囲指定して選択します。

概要

JListのアイテムをラバーバンドで範囲指定して選択します。

サンプルコード

#spanend
#spanadd
class RubberBandSelectionList<E extends ListItem> extends JList<E> {
#spanend
  private static final AlphaComposite ALPHA =
    AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .1f);
  private RubberBandListCellRenderer<E> renderer;
  private Color polygonColor;
  public RubberBandSelectionList(ListModel<E> model) {
    super(model);
  }

#spandel
#screenshot
#spanend
  @Override public void updateUI() {
    setSelectionForeground(null);
    setSelectionBackground(null);
    setCellRenderer(null);
    if (renderer == null) {
      renderer = new RubberBandListCellRenderer<E>();
    } else {
      removeMouseMotionListener(renderer);
      removeMouseListener(renderer);
    }
    super.updateUI();
    EventQueue.invokeLater(() -> {
      setCellRenderer(renderer);
      addMouseMotionListener(renderer);
      addMouseListener(renderer);
      setLayoutOrientation(JList.HORIZONTAL_WRAP);
      setVisibleRowCount(0);
      setFixedCellWidth(62);
      setFixedCellHeight(62);
      setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    });
    Color c = getSelectionBackground();
    int r = c.getRed();
    int g = c.getGreen();
    int b = c.getBlue();
    polygonColor = r > g ? r > b ? new Color(r, 0, 0) : new Color(0, 0, b)
                         : g > b ? new Color(0, g, 0) : new Color(0, 0, b);
  }

#spandel
**サンプルコード [#t7aa984b]
#spanend
 class MyList extends JList {
   private final Color pcolor;
   private final AlphaComposite alcomp =
     AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f);
   private final Polygon polygon = new Polygon();
   private final Line2D line = new Line2D.Double();
   private Point srcPoint = null;
   public MyList(ListModel model) {
     super(model);
     pcolor = makeColor();
     setLayoutOrientation(JList.HORIZONTAL_WRAP);
     setVisibleRowCount(0);
     setFixedCellWidth(62);
     setFixedCellHeight(62);
     setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     setCellRenderer(new ListCellRenderer() {
       public Component getListCellRendererComponent(JList list, Object value,
             int index, boolean isSelected, boolean cellHasFocus) {
         MyIcon icon = (MyIcon)getModel().getElementAt(index);
         icon.setSelected(isSelected);
         icon.setFocused(cellHasFocus);
         return icon;
       }
     });
     addMouseMotionListener(new MouseMotionAdapter() {
       public void mouseDragged(MouseEvent e){
         if(srcPoint==null) srcPoint = e.getPoint();
         Point destPoint = e.getPoint();
         polygon.reset();
         polygon.addPoint(srcPoint.x,  srcPoint.y);
         polygon.addPoint(destPoint.x, srcPoint.y);
         polygon.addPoint(destPoint.x, destPoint.y);
         polygon.addPoint(srcPoint.x,  destPoint.y);
         if(srcPoint.getX()==destPoint.getX() || srcPoint.getY()==destPoint.getY()) {
           line.setLine(srcPoint.getX(),srcPoint.getY(),
                        destPoint.getX(),destPoint.getY());
           setSelectedIndices(getIntersectsIcons(line));
         }else{
           setSelectedIndices(getIntersectsIcons(polygon));
         }
         repaint();
       }
     });
     addMouseListener(new MouseAdapter() {
       public void mouseReleased(MouseEvent e) {
         srcPoint = null;
         repaint();
       }
       public void mousePressed(MouseEvent e) {
         if(locationToIndex(e.getPoint())<0) {
           clearSelection();
           repaint();
         }else{
           int index = locationToIndex(e.getPoint());
           MyIcon icon = (MyIcon)getModel().getElementAt(index);
           Rectangle rect = getCellBounds(index,index);
           if(!rect.contains(e.getPoint())) {
             clearSelection();
             repaint();
           }
         }
       }
     });
   }
   public void paint(Graphics g) {
     super.paint(g);
     if(srcPoint==null) return;
     Graphics2D g2d = (Graphics2D) g;
     g2d.setColor(SystemColor.activeCaption);
     g2d.drawPolygon(polygon);
     g2d.setComposite(alcomp);
     g2d.setColor(pcolor);
     g2d.fillPolygon(polygon);
   }
   private int[] getIntersectsIcons(Shape p) {
     ListModel model = getModel();
     Vector list = new Vector(model.getSize());
     for(int i=0;i<model.getSize();i++) {
       Rectangle r = MyList.this.getCellBounds(i,i);
       if(p.intersects(r)) {
         list.add(new Integer(i));
       }
     }
     int[] il = new int[list.size()];
     for(int i=0;i<list.size();i++) {
       il[i] = ((Integer)list.get(i)).intValue();
     }
     return il;
   }
   private Color makeColor() {
     int r = SystemColor.activeCaption.getRed();
     int g = SystemColor.activeCaption.getGreen();
     int b = SystemColor.activeCaption.getBlue();
     if(r>g) {
       if(r>b) {
         return new Color(r,0,0);
       }else{
         return new Color(0,0,b);
       }
     }else{
       if(g>b) {
         return new Color(0,g,0);
       }else{
         return new Color(0,0,b);
       }
     }
   }
 }
  @Override protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (renderer != null && renderer.polygon != null) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setPaint(getSelectionBackground());
      g2.draw(renderer.polygon);
      g2.setComposite(ALPHA);
      g2.setPaint(polygonColor);
      g2.fill(renderer.polygon);
      g2.dispose();
    }
  }
#spanadd
}
#spanend
#spanadd
View in GitHub: Java, Kotlin
  • &jnlp;
  • &jar;
  • &zip;

解説

上記のサンプルでは、JListにマウスリスナーを設定してドラッグに応じた矩形を描画しています。

解説

JListにマウスリスナーを設定して、ドラッグに応じて矩形を描画しています。このとき、その矩形の内部にアイテムアイコンが重なる場合は、それを選択状態に変更しています。選択範囲が矩形にならずに直線になっている場合は、別途その直線と交差するアイテムを選択するようにしています。
  • JList内のアイテムの配置はJList#setLayoutOrientation(JList.HORIZONTAL_WRAP)メソッドを使っているため水平方向で整列される
  • ラバーバンド矩形内部に重なるアイテムアイコンを検索しそれをJList#setSelectedIndices(int[])で選択状態に変更
    • 選択範囲が矩形にならずに直線になっている場合は別途その直線と交差するアイテムを選択 PolygonではなくPath2Dを使用することでこれを回避
    • JDK 1.8.0以降なら以下をl.setSelectedIndices(IntStream.range(0, l.getModel().getSize()).filter(i -> p.intersects(l.getCellBounds(i, i))).toArray());で置き換え可能
JList内のアイテムの配置には、JList#setLayoutOrientation(JList.HORIZONTAL_WRAP)を使って、水平方向に整列された状態にしています。
#spanend
#spanadd
private int[] getIntersectsIcons(JList l, Shape p) {
#spanend
  ListModel model = l.getModel();
  List<Integer> list = new ArrayList<>(model.getSize());
  for (int i = 0; i < model.getSize(); i++) {
    Rectangle r = l.getCellBounds(i, i);
    if (p.intersects(r)) {
      list.add(i);
    }
  }
  // JDK 1.8.0以降のstreamでList<Integer>をプリミティブなint配列に変換:
  // return list.stream().mapToInt(i -> i).toArray();
  int[] il = new int[list.size()];
  for (int i = 0; i < list.size(); i++) {
    il[i] = list.get(i);
  }
  return il;
#spanadd
}
#spanend
#spanadd

参考リンク

参考リンク

コメント

コメント