SWT中的拖拽是使用的org.eclipse.swt.dnd。
有三個需要密切注意的類:
1、DragSource
2、DropTarget
3、Transfer
DragSource封裝了需要被拖拽的Control
DropTarget封裝了拖拽的目標Control,即是拖拽終點的容器
Transfer是一個轉換器,用於Java表示和平台指定的數據之間的相互轉換
根據以上,我們可以揣測:
1、只有被DragSource封裝了的Control對象才能被拖拽
2、只有被DropTarget封裝了的Control對象才能被放置拖拽對象
3、同一次操作中,DragSource和DropTarget所定義的Transfer必須匹配
了解了這些基礎,我們來看一個例子(該示例來自網絡):
package z_test_project; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.*; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.*; public class DNDExample { public static void main(String[] args) { Shell shell = new Shell(); shell.setBackground(new Color(null, 200, 200, 200)); shell.setLayout(new GridLayout(2, false)); // Create the tree and some tree items final Tree tree = new Tree(shell, SWT.NONE); TreeItem item1 = new TreeItem(tree, SWT.NONE); item1.setText("Item 1"); TreeItem item2 = new TreeItem(tree, SWT.NONE); item2.setText("Item 2"); // Create the drag source on the tree DragSource ds = new DragSource(tree, DND.DROP_MOVE); ds.setTransfer(new Transfer[] {TextTransfer.getInstance()}); ds.addDragListener(new DragSourceAdapter() { public void dragSetData(DragSourceEvent event) { // Set the data to be the first selected item's text event.data = tree.getSelection()[0].getText(); } }); // Create the text field final Text text = new Text(shell, SWT.NONE); // Create the drop target on the text field DropTarget dt = new DropTarget(text, DND.DROP_MOVE); dt.setTransfer(new Transfer[] {TextTransfer.getInstance()}); dt.addDropListener(new DropTargetAdapter() { public void drop(DropTargetEvent event) { // Set the text field's text to the text being dropped text.setText((String)event.data); } }); shell.pack(); shell.open(); Display display = Display.getDefault(); while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep(); display.dispose(); } }
效果如圖:

這只是實現了簡單的控件和控件之間的拖拽。
現在我們來實現兩個功能,從導航器或者操作系統里向編輯器中拖拽。
首先是導航器,大部分導航器使用了TreeViewer展示,org.eclipse.jface.viewers.StructuredViewer#addDragSupport方法為TreeViewer的Control添加了DragSource
即是創建DragSource的步驟已經預先完成了。
題外:使用CNF生成的導航器必然會用到擴展點org.eclipse.ui.navigator.navigatorContent
其下有元素navigatorContent,其下又有元素dropAssitant
從命名可以看出,它指定的類是用來封裝DropTarget和DropListener的
其內部實現有興趣的自己閱讀源碼。
這部分是為了讓導航器的內容可以在導航器內部拖拽。
然后我們寫一個編輯器,使用一個Text填充,Text部分源碼如下:
final Text text = new Text(composite, SWT.MULTI | SWT.BORDER); text.setText("測試頁1"); DropTarget dropTarget = new DropTarget(text, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK | DND.DROP_TARGET_MOVE); dropTarget.setTransfer(new Transfer[] { LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance() }); dropTarget.addDropListener(new DropTargetAdapter() { @Override public void drop(DropTargetEvent event) { text.setText(event.data == null ? null : event.data.toString()); } });
注意紅字部分,第一個LocalSelectionTransfer是為了讓DropTarget能匹配導航器拖拽的部分內容,第二個FileTransfer是為了讓其能匹配操作系統拖拽的文件。
以上即實現了拖拽功能。
這里提出一個問題,Text是如何識別到底一個拖拽進來的元素是否能夠放置的呢?
這里,就需要看Transfer#validate的實現了。
如果被拖拽的元素能通過DropTarget所指定的任何一個Transfer的validate,就會被該Transfer所處理,然后轉化為Java對象,應用到DropTarget封裝的Control上去。
