2012年9月9日 星期日

Java 拖曳檔案的動作:DnD

在 Java 上要跟其他應用程式交流資訊,可能需要的是透過 Drag & Drop(拖曳)或者 Clipborad(剪貼簿)來交換資料
在 Java 上就是透過 DnD 的方法來實作。
根據 [3] 的官方文件教學,DnD 分成兩個部分:

1、Drag and drop (DnD) support

2、Clipboard transfer through cut or copy and paste


文件中有提到只有某些 Component 有支援 DnD 的事件。

要註冊 DnD 事件,用法好像有好幾種?我目前試出來的方法是用 DropTargetListener
以下是初始化 DropTargetListener 的範例:
private DropTargetListener panelDropOutListener = new DropTargetListener() {
  @Override
  public void drop(DropTargetDropEvent dtde) {
    try {
      Transferable tf = dtde.getTransferable();

      // The dragged thing is a file list.
      if(tf.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
        // Accept the drop event and get the dropped information.
        int action = dtde.getDropAction();
        dtde.acceptDrop(action);

        // Get the dropped information.
        List<?> list = (List<?>) tf.getTransferData(DataFlavor.javaFileListFlavor);
        for (Object o : list) {
          System.out.println("file=" + o);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  @Override
  public void dropActionChanged(DropTargetDragEvent dtde) {}
  
  @Override
  public void dragOver(DropTargetDragEvent dtde) {}
  
  @Override
  public void dragExit(DropTargetEvent dte) {}
  
  @Override
  public void dragEnter(DropTargetDragEvent dtde) {}
};

其中可以看到 Drag & Drop 有分成好幾種事件:
  • dragEnter:滑鼠拖曳著某個東西進入區域。
  • dragExit:滑鼠拖曳著某個東西離開區域。
  • dragOver:滑鼠拖曳著某個東西在區域內。(當滑鼠正在區域內時,這個事件會一直不斷觸發)
  • dropActionChanged:字面上是滑鼠放開某個東西的動作改變了,不過我還沒測試出是什麼動作會產生這個事件 XD
  • drop:滑鼠拖曳著某個東西,並在區域內放開。

在 Drop 的事件中,用 DropTargetDropEvent.getTransferable() 取得 Drop 事件丟下的東西
接著檢查 Drop 下來的是什麼東西,這裡是只檢查是否為檔案列表(也就是拖曳檔案過去的狀況)
如果是檔案列表的話,則將 Drop 的資訊接受,然後把這些資訊轉成 List。
印出的資訊如下:
file=D:\test.txt
以上可以看出拖曳檔案時,Drop 會帶上檔案的完整路徑。

另外如果沒有呼叫 DropTargetDropEvent.acceptDrop() 的話,會丟出以下的 Exception
表示因為沒有接收 Drop 的資訊,因此沒有東西可以處理。
java.awt.dnd.InvalidDnDOperationException: No drop current

接著假設我們用的是 JTextPane,以下是註冊 Drop 事件的範例:
public class MainPanel extends JFrame {
  private static final long serialVersionUID = 1L;
  private JTextPane mainPanel = null;
  
  public MainPanel () {
    this.initialPanel();
    this.initialJFrame();
  }
  
  /**
   * Initialize JFrame.
   */
  private void initialJFrame () {
    this.add(this.mainPanel);
    
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);
    this.setSize(200, 100);
    this.setAlwaysOnTop(true);
    this.setVisible(true);
  }
  
  /**
   * Initialize the panel in JFrame.
   */
  private void initialPanel () {
    this.mainPanel = new JTextPane();
    this.mainPanel.setEditable(false);
    
    try {
      // Initial drag & drop event.
      DropTarget target = new DropTarget();
      target.setActive(true);
      target.addDropTargetListener(this.panelDropOutListener);
      
      // Add event of drag & drop to JTextPane.
      this.mainPanel.setDropTarget(target);
    } catch (TooManyListenersException e) {}
  }

  private DropTargetListener panelDropOutListener; // Ignore the initialization.
}


參考資料:
1、請問如何在Applet上設計拖曳檔案上傳..
2、DnD drag files
3、The Java Tutorial:Introduction to DnD

沒有留言: