• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JListの項目をドラッグ&ドロップ
#navi(../)
*JListの項目をドラッグ&ドロップ [#vdb92e79]
>編集者:[[Terai Atsuhiro>terai]]~
作成日:2004-02-16~
更新日:&lastmod;
---
category: swing
folder: DnDList
title: JListの項目をドラッグ&ドロップ
tags: [JList, DragAndDrop]
author: aterai
pubdate: 2004-02-16
description: JListをドラッグ&ドロップして項目を入れ替えます。
image: https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTLb3DW2ZI/AAAAAAAAAXk/8VfeirUfaoo/s800/DnDList.png
---
* 概要 [#summary]
`JList`をドラッグ&ドロップして項目を入れ替えます。

#contents
#download(https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTLb3DW2ZI/AAAAAAAAAXk/8VfeirUfaoo/s800/DnDList.png)

**概要 [#va15d9c9]
JListをドラッグ&ドロップして、項目を入れ替えます。
* サンプルコード [#sourcecode]
#code(link){{
@Override protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  if (targetIndex >= 0) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setPaint(lineColor);
    g2.fill(targetLine);
    g2.dispose();
  }
}

#screenshot
private void initTargetLine(Point p) {
  Rectangle rect = getCellBounds(0, 0);
  int cellHeight = rect.height;
  int lineHeight = 2;
  int modelSize  = getModel().getSize();
  targetIndex = -1;
  targetLine.setSize(rect.width, lineHeight);
  for (int i = 0; i < modelSize; i++) {
    rect.setLocation(0, cellHeight * i - cellHeight / 2);
    if (rect.contains(p)) {
      targetIndex = i;
      targetLine.setLocation(0, i * cellHeight);
      break;
    }
  }
  if (targetIndex < 0) {
    targetIndex = modelSize;
    targetLine.setLocation(0, targetIndex * cellHeight - lineHeight);
  }
}

**サンプルコード [#kadf6356]
 private Rectangle2D raCueLine = new Rectangle2D.Float();
 private Rectangle2D midArea   = new Rectangle2D.Float();
 public void dragOver(final DropTargetDragEvent e) {
   Graphics2D g2  = (Graphics2D) list1.getGraphics();
   int cellHeight = (int) list1.getCellBounds(0,0).getHeight();
   int cellWidht  = (int) list1.getCellBounds(0,0).getWidth();
   boolean flag   = false;
   for(int i=0;i<=model.getSize();i++) {
     midArea.setRect(0, cellHeight*i - (int) (cellHeight/2), cellWidht, cellHeight);
     if(midArea.contains(e.getLocation())) {
       flag = true;
       targetIndex = i;
       g2.setColor(lineColor);
     }else{
       g2.setColor(list1.getBackground());
     }
     raCueLine.setRect(0, i*cellHeight, cellWidht, 2);
     g2.fill(raCueLine);
   }
   //セルの間にターゲットが無かった場合リストの一番下にラインを引く
   if(!flag) {
     targetIndex = model.getSize();
     raCueLine.setRect(0, targetIndex*cellHeight, cellWidht, 2);
     g2.setColor(lineColor);
     g2.fill(raCueLine);
   }
   if(isDragAcceptable(e)) {
     e.acceptDrag(e.getDropAction());
   }else{
     e.rejectDrag();
   }
   //選択がずれないように…
   list1.setSelectedIndex(draggedIndex);
 }
@Override public void dragOver(final DropTargetDragEvent e) {
  if (isDragAcceptable(e)) {
    e.acceptDrag(e.getDropAction());
  } else {
    e.rejectDrag();
    return;
  }
  initTargetLine(e.getLocation());
  repaint();
}

 public void drop(DropTargetDropEvent e) {
   Point point = e.getLocation();
   Transferable t = e.getTransferable();
   DataFlavor[] f = t.getTransferDataFlavors();
   try {
     if(isDropAcceptable(e)) {
       Component comp = (Component) t.getTransferData(f[0]);
       Object str = model.getElementAt(draggedIndex);
       if(targetIndex==draggedIndex) {
         list1.setSelectedIndex(targetIndex);
       }else if(targetIndex<draggedIndex) {
         model.removeElementAt(draggedIndex);
         model.insertElementAt(str, targetIndex);
         list1.setSelectedIndex(targetIndex);
       }else{
         model.insertElementAt(str, targetIndex);
         model.removeElementAt(draggedIndex);
         list1.setSelectedIndex(targetIndex-1);
       }
       e.dropComplete(true);
     }else{
       e.dropComplete(false);
     }
   }catch(UnsupportedFlavorException ex) {
     e.dropComplete(false);
   }catch(IOException ie) {
     e.dropComplete(false);
   }
   e.dropComplete(false);
   targetIndex = -1;
   list1.repaint();
 }
@Override public void drop(DropTargetDropEvent e) {
  DefaultListModel model = (DefaultListModel) getModel();
  Transferable t = e.getTransferable();
  DataFlavor[] f = t.getTransferDataFlavors();
  try {
    if (isDropAcceptable(e)) {
      Component comp = (Component) t.getTransferData(f[0]);
      Object str = model.getElementAt(draggedIndex);
      if (targetIndex == draggedIndex) {
        setSelectedIndex(targetIndex);
      } else if (targetIndex < draggedIndex) {
        model.removeElementAt(draggedIndex);
        model.insertElementAt(str, targetIndex);
        setSelectedIndex(targetIndex);
      } else {
        model.insertElementAt(str, targetIndex);
        model.removeElementAt(draggedIndex);
        setSelectedIndex(targetIndex - 1);
      }
      e.dropComplete(true);
    } else {
      e.dropComplete(false);
    }
  } catch (UnsupportedFlavorException | IOException ex) {
    e.dropComplete(false);
  }
  e.dropComplete(false);
  targetIndex = -1;
  repaint();
}
}}

-&jnlp;
-&jar;
-&zip;
* 解説 [#explanation]
上記のサンプルでは、ドラッグソースとドラッグターゲットの両方を`JList`自身に設定して、項目をドラッグ&ドロップしているように見せかけています。

**解説 [#na78421d]
上記のサンプルでは、ドラッグソースとドラッグターゲットの両方をJList自身に設定して、項目をドラッグ&ドロップしているように見せかけています。
- 複数アイテムを選択して移動する場合は[[TransferHandlerを使ったJListのドラッグ&ドロップによる並べ替え>Swing/DnDReorderList]]のサンプルなどを参照

複数アイテムを選択しての移動には対応していません。
* 参考リンク [#reference]
- [https://docs.oracle.com/javase/tutorial/uiswing/dnd/intro.html Introduction to Drag and Drop and Data Transfer]
- [https://community.oracle.com/thread/1487942 Swing (Archive) - DND from a JList with a single gesture]
- [https://community.oracle.com/thread/1487416 Swing (Archive) - Smoother Drag Drop JList JTable]
- [[TransferHandlerを使ったJListのドラッグ&ドロップによる並べ替え>Swing/DnDReorderList]]
- [[JListのアイテムをラバーバンドで複数選択、ドラッグ&ドロップで並べ替え>Swing/DragSelectDropReordering]]

**参考リンク [#qca3b1e2]
-[[How to Use Drag and Drop and Data Transfer>http://java.sun.com/docs/books/tutorial/uiswing/misc/dnd.html]]
-[[DND from a JList with a single gesture>http://forum.java.sun.com/thread.jsp?forum=57&thread=465997]]
-[[Smoother Drag Drop JList JTable>http://forum.java.sun.com/thread.jsp?forum=57&thread=470025]]
* コメント [#comment]
#comment
- 以下を修正しました。 -- &user(aterai); &new{2006-04-24 (月) 22:47:06};
-- ドラッグで選択されたアイテムがずれにくいように修正
-- ドロップしたあとアイテムが選択状態になるように修正
-- アイテムの無い場所にドラッグすると一番最後の項目の下にラインを引くように修正(以前は一番下のアイテムの下半分にドラッグした場合のみ、そこに線を引いていた)
- アイテムを複数選択した状態でドラッグすると`Exception`が発生する不具合を修正しました。 -- &user(aterai); &new{2006-06-27 (火) 16:34:22};
- ドラッグ中マウスが`JList`の外に出た場合、カーソルを変更するように変更しました。 -- &user(aterai); &new{2007-04-02 (月) 16:26:22};
- `JTabbedPane`に`JList`を追加し、タブを二つ作りました。`JList`の項目を他のタブへ`D&D`すると、`mouseReleased`メソッドが反応しないのですが、どうすれば回避できますでしょうか。 -- &user(sao); &new{2007-09-22 (土) 14:57:27};
-- %%削除しました `src2.zip`%% を作って`XP`+`JDK 1.6.0_02`で試してみたのですが、`JList`の項目を他のタブへの`D&D`が不可のようです。環境が違うのかな? -- &user(aterai); &new{2007-09-22 (土) 16:16:29};
- ぉー!ファイル、わざわざありがとうございます!自分なりに頑張ってます。私がやりたのは`JList`の項目をタブへ`D&D`して項目に書かれている内容を他のタブ(の持ってる`JList`)へ渡したいんです。現状は、`2`つ以上の項目なら渡せて、`1`つだとエラーがでてしまいます。よくわかっていないまま進めてるので、全然わからないです(汗) -- &user(sao); &new{2007-09-27 (木) 20:03:38};
-- あ、`src2.zip`は的外れでしたね。このページの`DnDList`を`JTabbedPane`に入れて、項目をタブタイトルにドロップすると`Exception`の発生するバグがあるのかも?と勘違いしていました。このページのサンプルを改造するなら、`src2.zip`ではなく、[https://ateraimemo.com/swing/dropontabtitle/src.zip こちらのソース(名前を変更しました)]、チュートリアルなら[https://docs.oracle.com/javase/tutorial/uiswing/examples/dnd/index.html#DragListDemo Drag and Drop and Data Transfer: Examples (The Java™ Tutorials > Creating a GUI with Swing > Drag and Drop and Data Transfer)]が参考になるかも。 -- &user(aterai); &new{2007-09-28 (金) 02:24:23};
- `src3`ありがとうございます☆軽快に動きますね!すごく!`src3`ですが、`DnDList`に`setEnabled(true);`を追加しました。が、まったくわからず…思いのほか、`2`項目以上の`D&D`って難しいですネ(汗 -- &user(sao); &new{2007-09-28 (金) 17:50:42};

**コメント [#m0be05ec]
- 以下を修正しました。 -- [[terai]] &new{2006-04-24 (月) 22:47:06};
--ドラッグで選択されたアイテムがずれにくいように修正
--ドロップしたあとアイテムが選択状態になるように修正
--アイテムの無い場所にドラッグすると一番最後の項目の下にラインを引くように修正(以前は一番下のアイテムの下半分にドラッグした場合のみ、そこに線を引いていた)
- アイテムを複数選択した状態でドラッグするとExceptionが発生する不具合を修正しました。 -- [[terai]] &new{2006-06-27 (火) 16:34:22};

#comment