理解了拖拽的這些概念之后,下面我們就著一個簡單的例子來運用一下。如圖所示,這個例子中,左面的tree是DragSource,右面的table是DropTarget,我們從左面的tree中選擇一條,拖進右邊的table中:

我們先從DragSource開始:
//獲得一個TextTransfer的實例,TextTransfer是Transfer的一個子類,
//他提供將普通文本以Java String的表示轉(zhuǎn)換為特定于平臺的表示的機制。
TextTransfer textTransfer=TextTransfer.getInstance();
//構造一個普通的tree
dragTree=new Tree(parent,SWT.FULL_SELECTION|SWT.SINGLE);
//將dragTree與DragSource綁定(一個widget只能綁定在一個DragSource),
//并允許數(shù)據(jù)可以從DragSource被MOVE或COPY
DragSource source=new DragSource(dragTree,DND.DROP_MOVE|DND.DROP_COPY);
//指定允許的textTransfer類型,可以是多個。
source.setTransfer(new Transfer[] { textTransfer });
//注冊DragSourceListener。處理拖操作的一些事件
source.addDragListener(new MyDragSourceListener());
在MyDragSourceListener中有以下3個方法:
// 指定拖動開始的執(zhí)行策略。
public void dragStart(DragSourceEvent event){
//在這里可以設置一些條件,如果不符合條件,比方說選中的treeitem是根,
? ? //則不可拖動
? ? if(treeitem是根){
? event.doit=false;
? ? }
}
//dragSetData方法在dragStart通過之后才被調(diào)用。這個方法可能會因為同一種傳輸
//類型多次set或不同的多種傳輸類型的set而被多次調(diào)用,象windows等有些平臺
//中,dropTarget可以在鼠標移動的過程中請求數(shù)據(jù),但是在Motif等平臺中,只可以
//在drop操作完成之后才可以請求數(shù)據(jù),所以在這個方法中不要假設drag and drop操
//作已經(jīng)完成.在這個方法中是無法知道data將被drop到哪里.
//set的Data也要符合指定的Transfer的format類型。
? ? public void dragSetData(DragSourceEvent event){
? ? //在這里可以為DragSourceEvent添加數(shù)據(jù),這個方法在拖動過程中
//會被不停的調(diào)用
? ? ? ? TreeItem selection = DragAndDrop.this.dragTree.getSelection()[0];
? ? ? ? event.data=selection.getText();
? ? }
? ? // 根據(jù)事先指定好的操作類型來處理操作結果
? ? public void dragFinished(DragSourceEvent event){
? ? ? ? if(event.detail==DND.DROP_MOVE){
? ? ? ? ? ? //remove selection TreeItem
? ? ? ? }
? ? }
其次是DropTarget
// 將dropTable指定為Drop Target,
? ? DropTarget target=new DropTarget(dropTable,DND.DROP_MOVE|DND.DROP_COPY|DND.DROP_DEFAULT);
? ? target.setTransfer(new Transfer[] {textTransfer });
? ? target.addDropListener(new MyDropTargetListener());
對于MyDropTargetListener
class MyDropTargetListener implements DropTargetListener{
? ? //dragEnter事件在drag and drop動作開始,并且鼠標進入了target widget的范圍內(nèi)時被調(diào)用。
? ? public void dragEnter(DropTargetEvent event){
? ? ? ? //在dragEnter中應用可以定義default operation.如果一個drop target在創(chuàng)建的時候被指定為
? ? ? ? //帶有DND.DROP_DEFAULT,那么在拖動的過程中如果沒有輔助按鍵被按下,則drop target就是DND.DROP_DEFAULT的。
? ? ? ? //應用可以通過改變event.detail來指定default operation。如果應用沒有具體指定DND.DROP_DEFAULT的操作,
? ? ? ? //平臺會默認將DND.DROP_DEFAULT設置為DND.DROP_MOVE。
? ? ? ? //另外DND.DROP_DEFAULT的值也可以在dragOperationChanged中設置。
? ? ? ?
? ? ? ? if(event.detail==DND.DROP_DEFAULT){
? ? ? ? ? //給event.detail賦的值必須是event.operations中的一個,event.operations中
? ? ? ? ? //的操作都是DragSource所支持的.
? ? ? ? ? if((event.operations&DND.DROP_COPY)!=0){
? ? ? ? ? ? event.detail=DND.DROP_COPY;
? ? ? ? ? }else{
? ? ? ? ? ? event.detail=DND.DROP_NONE;
? ? ? ? ? }
? ? ? ? }
? ? ? ?
? ? ? ? //drop target可以選擇性的按照傳輸類型來處理.dragEnter event有兩個屬性
? ? ? ? //event.currentType 是應用設置的默認類型,以TransferData對象形式表現(xiàn),
? ? ? ? //event.dataTypes 是drag source支持的所有類型的列表,以TransferData數(shù)組形式表現(xiàn),
? ? ? ? //我們可以將event.currentType設置成event.dataTypes中的任意一個。
? ? ? ? //這些屬性也可以在dragOver, dragOperationChanged以及dropAccept事件中設置。
? ? ? ? for(int i=0;i<event.dataTypes.length;i++){
? ? ? ? ? if(textTransfer.isSupportedType(event.dataTypes
)){
? ? ? ? ? ? event.currentDataType=event.dataTypes
;
? ? ? ? ? ? //只允許COPY
? ? ? ? ? ? if(event.detail!=DND.DROP_COPY){
? ? ? ? ? ? ? ? event.detail=DND.DROP_NONE;
? ? ? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? ? }
? ? ? ? }
? ? }
? ? //dragOver event在光標進入drop target widget時會被重復不停的調(diào)用.
? ? //如果光標是靜止的,dragOver event依然會有規(guī)則的按一定時間間隔被調(diào)用.
? ? //這個方法一般在drop target是table或tree時用得比較多,可以根據(jù)不同的item而改變操作.
? ? public void dragOver(DropTargetEvent event){
? ? ? ? //event.feedback設置當widget處于光標下時應該給用戶一個什么樣的feedback.
? ? ? ? //dragOver event.feedback 值描述
? ? ? ? //DND.FEEDBACK_SELECT 使光標下的item被選中,限于table and trees.
? ? ? ? //DND.FEEDBACK_SCROLL 使widget可以滾動以便于用戶可以drop在當前看不見的item上,限于table and trees.
? ? ? ? //DND.FEEDBACK_EXPAND 使當前光標下的item展開以便于用戶在sub item上drop,限于trees.
? ? ? ? //DND.FEEDBACK_INSERT_BEFORE 在item處于光標下之前顯示一個插入標記,限于tables and trees.
? ? ? ? //DND.FEEDBACK_INSERT_AFTER ? 在item處于光標下之后顯示一個插入標記,限于tables and trees.
? ? ? ? //DND.FEEDBACK_NONE ? 沒有任何效果.
? ? ? ? event.feedback=DND.FEEDBACK_SELECT|DND.FEEDBACK_SCROLL;
? ? ? ? if(textTransfer.isSupportedType(event.currentDataType)){
? ? ? ? ? String t=(String)(textTransfer.nativeToJava(event.currentDataType));
? ? ? ? ? if(t!=null){
? ? ? ? ? ? System.out.println(t);
? ? ? ? ? }
? ? ? ? }
? ? }
? ? //當用戶按下或放開輔助按鍵時,例如Ctrl, Shift, Command, Option。則dragOperationChanged事件發(fā)生。
? ? //輔助按鍵可以改變即將進行的操作。例如:
? ? //Ctrl key is down, a copy is requested,
? ? //Ctrl and Shift keys are both down, a link is requested
? ? //Shift key is down, a move is requested
? ? //When no modifier keys are pressed, the default operation is requested.
? ? public void dragOperationChanged(DropTargetEvent event){
? ? ? ? if(event.detail==DND.DROP_DEFAULT){
? ? ? ? ? event.detail=DND.DROP_COPY;
? ? ? ? }else{
? ? ? ? ? event.detail=DND.DROP_NONE;
? ? ? ? }
? ? ? ? // allow text to be moved but files should only be copied
? ? ? ? if(fileTransfer.isSupportedType(event.currentDataType)){
? ? ? ? ? if(event.detail!=DND.DROP_COPY){
? ? ? ? ? ? event.detail=DND.DROP_NONE;
? ? ? ? ? }
? ? ? ? }
? ? }
? ? //當光標離開drop target widget時,dragLeave事件發(fā)生. 如果你在dragEnter中分配了一些資源,
? ? //就應該在dragLeave中釋放.dragLeave事件在用戶通過Escape鍵取消Drag and Drop操作時也會發(fā)生
? ? //剛好在drop操作被執(zhí)行之前.
? ? public void dragLeave(DropTargetEvent event){
? ? }
? ? //dropAccept事件為應用提供了最后一次定義數(shù)據(jù)類型的機會,定義的數(shù)據(jù)類型將被返回到drop事件.
? ? //這些是通過向event.currentDataType賦event.dataTypes中的值來實現(xiàn)的.
? ? public void dropAccept(DropTargetEvent event){
? ? }
? ? //如果在之前的事件中得到了有效的操作和currentDataType,那么當用戶在drop target上松開鼠標時,drop事件會發(fā)生。
? ? //event.data屬性包含了請求到的數(shù)據(jù),event.type包含了Transfer的類型.
? ? //data是event.currentDataType中定義的類型.
? ? public void drop(DropTargetEvent event){
? ? ? ? if(textTransfer.isSupportedType(event.currentDataType)){
? ? ? ? ? String text=(String)event.data;
? ? ? ? ? TableItem item=new TableItem(dropTable,SWT.NONE);
? ? ? ? ? item.setText(text);
? ? ? ? }
? ? ? ? if(fileTransfer.isSupportedType(event.currentDataType)){
? ? ? ? ? String[] files=(String[])event.data;
? ? ? ? ? for(int i=0;i<files.length;i++){
? ? ? ? ? ? TableItem item=new TableItem(dropTable,SWT.NONE);
? ? ? ? ? ? item.setText(files
);
? ? ? ? ? }
? ? ? ? }
? ? }
? }
package
?net.advanced.eclipse.sample.views;
import
?org.eclipse.swt.SWT;
import
?org.eclipse.swt.dnd.DND;
import
?org.eclipse.swt.dnd.DragSource;
import
?org.eclipse.swt.dnd.DragSourceEvent;
import
?org.eclipse.swt.dnd.DragSourceListener;
import
?org.eclipse.swt.dnd.DropTarget;
import
?org.eclipse.swt.dnd.DropTargetEvent;
import
?org.eclipse.swt.dnd.DropTargetListener;
import
?org.eclipse.swt.dnd.FileTransfer;
import
?org.eclipse.swt.dnd.TextTransfer;
import
?org.eclipse.swt.dnd.Transfer;
import
?org.eclipse.swt.widgets.Composite;
import
?org.eclipse.swt.widgets.Table;
import
?org.eclipse.swt.widgets.TableColumn;
import
?org.eclipse.swt.widgets.TableItem;
import
?org.eclipse.swt.widgets.Tree;
import
?org.eclipse.swt.widgets.TreeItem;
import
?org.eclipse.ui.part.ViewPart;
/**
?*?@Title:?DragAndDrop.java
?*?@Copyright:
?*?@Company:
?*?@Created?on?2005-12-02?14:34:40
?*?
@author
?孫其弘
?*?
@version
?$Revision:?1.11?$
?*?
@since
?1.0
?
*/
public
?
class
?DragAndDrop?
extends
?ViewPart{
????
private
?Tree?dragTree;
????
private
?Table?dropTable;
????
private
?TextTransfer?textTransfer;
????
private
?FileTransfer?fileTransfer;
????
public
?
void
?createPartControl(Composite?parent){
????????
/*
?Transfer是一個可以提供數(shù)據(jù)在Java?representation與platform?specific?representation
?????????*?之間交互的抽象類.下面是幾個format:
?????????*?TextTransfer?String?"hello?world"?
?????????*?RTFTransfer?String?"{\\rtf1\\b\\i?hello?world}"?
?????????*?FileTransfer?String[]?new?String[]?{file1.getAbsolutePath(),?file2.getAbsolutePath()}?
?????????*?
?????????*?TransferData包含了很多特定于平臺的公用的屬性,應用不應該直接去訪問這些屬性。
?????????*?如果真的有必要去訪問這些屬性,那么我們可以通過擴展Transfer類來完成對特定平臺的額外操作。
?????????
*/
????????textTransfer
=
TextTransfer.getInstance();
????????fileTransfer
=
FileTransfer.getInstance();
????????dragTree
=
new
?Tree(parent,SWT.FULL_SELECTION
|
SWT.SINGLE);
????????
for
(
int
?i
=
0
;i
<
10
;i
++
){
????????????TreeItem?item
=
new
?TreeItem(dragTree,SWT.NONE);
????????????item.setText(
"
treeitem
"
+
i);
????????????
for
(
int
?i2
=
0
;i2
<
5
;i2
++
){
????????????????TreeItem?subitem
=
new
?TreeItem(item,SWT.NONE);
????????????????subitem.setText(
"
subtreeitem
"
+
i2);
????????????}
????????}
????????
//
將dragLabel指定為DragSource(一個widget只能幫定在一個DragSource),
????????
//
并允許數(shù)據(jù)可以從DragSource被MOVE或COPY
????????DragSource?source
=
new
?DragSource(dragTree,DND.DROP_MOVE
|
DND.DROP_COPY);
????????source.setTransfer(
new
?Transfer[]?{?textTransfer?});
//
?指定允許的傳輸類型
????????source.addDragListener(
new
?MyDragSourceListener());
????????dropTable
=
new
?Table(parent,SWT.BORDER
|
SWT.FULL_SELECTION
|
SWT.SINGLE);
????????fillTable();
????????
//
?將dropTable指定為Drop?Target,
????????DropTarget?target
=
new
?DropTarget(dropTable,DND.DROP_MOVE
|
DND.DROP_COPY
|
DND.DROP_DEFAULT);
????????target.setTransfer(
new
?Transfer[]?{textTransfer?});
????????target.addDropListener(
new
?MyDropTargetListener());
????}
????
class
?MyDragSourceListener?
implements
?DragSourceListener{
????????
//
?指定拖動開始的執(zhí)行策略。
????????
public
?
void
?dragStart(DragSourceEvent?event){
????????????
if
(((DragSource)event.widget).getControl()?
instanceof
?Tree){
????????????????TreeItem?selection?
=
?DragAndDrop.
this
.dragTree.getSelection()[
0
];
????????????????
if
(selection.getText().length()
==
0
){
????????????????????event.doit
=
false
;
????????????????}?
????????????}
????????}
????????
//
dragSetData方法在dragStart通過之后才被調(diào)用。這個方法可能會因為同一種傳輸類型多次set或
????????
//
不同的多種傳輸類型的set而被多次調(diào)用,象windows等有些平臺中,dropTarget可以在鼠標移動的
????????
//
過程中請求數(shù)據(jù),但是在Motif等平臺中,只可以在drop操作完成之后才可以請求數(shù)據(jù),所以在這個方
????????
//
法中不要假設drag?and?drop操作已經(jīng)完成.在這個方法中是無法知道data將被drop到哪里.
????????
//
set的Data也要符合指定的Transfer的format類型。
????????
public
?
void
?dragSetData(DragSourceEvent?event){
????????????
if
(TextTransfer.getInstance().isSupportedType(event.dataType)){
????????????????
if
(((DragSource)event.widget).getControl()?
instanceof
?Tree){
????????????????????TreeItem?selection?
=
?DragAndDrop.
this
.dragTree.getSelection()[
0
];
????????????????????event.data
=
selection.getText();
????????????????}
????????????}
????????}
????????
//
?根據(jù)事先指定好的操作類型來處理操作結果
????????
public
?
void
?dragFinished(DragSourceEvent?event){
????????????
if
(event.detail
==
DND.DROP_MOVE){
????????????????
if
(((DragSource)event.widget).getControl()?
instanceof
?Tree){
????????????????????TreeItem?selection?
=
?DragAndDrop.
this
.dragTree.getSelection()[
0
];
????????????????????selection.removeAll();
????????????????}
????????????}
????????}
????}
????
class
?MyDropTargetListener?
implements
?DropTargetListener{
????????
//
dragEnter事件在drag?and?drop動作開始,并且鼠標進入了target?widget的范圍內(nèi)時被調(diào)用。
????????
public
?
void
?dragEnter(DropTargetEvent?event){
????????????
//
在dragEnter中應用可以定義default?operation.如果一個drop?target在創(chuàng)建的時候被指定為
????????????
//
帶有DND.DROP_DEFAULT,那么在拖動的過程中如果沒有輔助按鍵被按下,則drop?target就是DND.DROP_DEFAULT的。
????????????
//
應用可以通過改變event.detail來指定default?operation。如果應用沒有具體指定DND.DROP_DEFAULT的操作,
????????????
//
平臺會默認將DND.DROP_DEFAULT設置為DND.DROP_MOVE。
????????????
//
另外DND.DROP_DEFAULT的值也可以在dragOperationChanged中設置。
????????????
????????????
if
(event.detail
==
DND.DROP_DEFAULT){
????????????????
//
給event.detail賦的值必須是event.operations中的一個,event.operations中
????????????????
//
的操作都是DragSource所支持的.?
????????????????
if
((event.operations
&
DND.DROP_COPY)
!=
0
){
????????????????????event.detail
=
DND.DROP_COPY;
????????????????}
else
{
????????????????????event.detail
=
DND.DROP_NONE;
????????????????}
????????????}
????????????
????????????
//
drop?target可以選擇性的按照傳輸類型來處理.dragEnter?event有兩個屬性
????????????
//
event.currentType?是應用設置的默認類型,以TransferData對象形式表現(xiàn),
????????????
//
event.dataTypes?是drag?source支持的所有類型的列表,以TransferData數(shù)組形式表現(xiàn),?
????????????
//
我們可以將event.currentType設置成event.dataTypes中的任意一個。
????????????
//
這些屬性也可以在dragOver,?dragOperationChanged以及dropAccept事件中設置。
????????????
for
(
int
?i
=
0
;i
<
event.dataTypes.length;i
++
){
????????????????
if
(textTransfer.isSupportedType(event.dataTypes[i])){
????????????????????event.currentDataType
=
event.dataTypes[i];
????????????????????
//
只允許COPY
????????????????????
if
(event.detail
!=
DND.DROP_COPY){
????????????????????????event.detail
=
DND.DROP_NONE;
????????????????????}
????????????????????
break
;
????????????????}
????????????}
????????}
????????
//
dragOver?event在光標進入drop?target?widget時會被重復不停的調(diào)用.?
????????
//
如果光標是靜止的,dragOver?event依然會有規(guī)則的按一定時間間隔被調(diào)用.?
????????
//
這個方法一般在drop?target是table或tree時用得比較多,可以根據(jù)不同的item而改變操作.
????????
public
?
void
?dragOver(DropTargetEvent?event){
????????????
//
event.feedback設置當widget處于光標下時應該給用戶一個什么樣的feedback.?
????????????
//
dragOver?event.feedback?值描述?
????????????
//
DND.FEEDBACK_SELECT??使光標下的item被選中,限于table?and?trees.?
????????????
//
DND.FEEDBACK_SCROLL??使widget可以滾動以便于用戶可以drop在當前看不見的item上,限于table?and?trees.??
????????????
//
DND.FEEDBACK_EXPAND??使當前光標下的item展開以便于用戶在sub?item上drop,限于trees.?
????????????
//
DND.FEEDBACK_INSERT_BEFORE??在item處于光標下之前顯示一個插入標記,限于tables?and?trees.?
????????????
//
DND.FEEDBACK_INSERT_AFTER???在item處于光標下之后顯示一個插入標記,限于tables?and?trees.??
????????????
//
DND.FEEDBACK_NONE????沒有任何效果.?
????????????event.feedback
=
DND.FEEDBACK_SELECT
|
DND.FEEDBACK_SCROLL;
????????????
if
(textTransfer.isSupportedType(event.currentDataType)){
????????????????String?t
=
(String)(textTransfer.nativeToJava(event.currentDataType));
????????????????
if
(t
!=
null
){
????????????????????System.out.println(t);
????????????????}
????????????}
????????}
????????
//
當用戶按下或放開輔助按鍵時,例如Ctrl,?Shift,?Command,?Option。則dragOperationChanged事件發(fā)生。
????????
//
輔助按鍵可以改變即將進行的操作。例如:
????????
//
Ctrl?key?is?down,?a?copy?is?requested,
????????
//
Ctrl?and?Shift?keys?are?both?down,?a?link?is?requested
????????
//
Shift?key?is?down,?a?move?is?requested
????????
//
When?no?modifier?keys?are?pressed,?the?default?operation?is?requested.?
????????
public
?
void
?dragOperationChanged(DropTargetEvent?event){
????????????
if
(event.detail
==
DND.DROP_DEFAULT){
????????????????event.detail
=
DND.DROP_COPY;
????????????}
else
{
????????????????event.detail
=
DND.DROP_NONE;
????????????}
????????????
//
?allow?text?to?be?moved?but?files?should?only?be?copied
????????????
if
(fileTransfer.isSupportedType(event.currentDataType)){
????????????????
if
(event.detail
!=
DND.DROP_COPY){
????????????????????event.detail
=
DND.DROP_NONE;
????????????????}
????????????}
????????}
????????
//
當光標離開drop?target?widget時,dragLeave事件發(fā)生.?如果你在dragEnter中分配了一些資源,
????????
//
就應該在dragLeave中釋放.dragLeave事件在用戶通過Escape鍵取消Drag?and?Drop操作時也會發(fā)生
????????
//
剛好在drop操作被執(zhí)行之前.
????????
public
?
void
?dragLeave(DropTargetEvent?event){
????????}
????????
//
dropAccept事件為應用提供了最后一次定義數(shù)據(jù)類型的機會,定義的數(shù)據(jù)類型將被返回到drop事件.?
????????
//
這些是通過向event.currentDataType賦event.dataTypes中的值來實現(xiàn)的.
????????
public
?
void
?dropAccept(DropTargetEvent?event){
????????}
????????
//
如果在之前的事件中得到了有效的操作和currentDataType,那么當用戶在drop?target上松開鼠標時,drop事件會發(fā)生。
????????
//
event.data屬性包含了請求到的數(shù)據(jù),event.type包含了Transfer的類型.?
????????
//
data是event.currentDataType中定義的類型.
????????
public
?
void
?drop(DropTargetEvent?event){
????????????
if
(textTransfer.isSupportedType(event.currentDataType)){
????????????????String?text
=
(String)event.data;
????????????????TableItem?item
=
new
?TableItem(dropTable,SWT.NONE);
????????????????item.setText(text);
????????????}
????????????
if
(fileTransfer.isSupportedType(event.currentDataType)){
????????????????String[]?files
=
(String[])event.data;
????????????????
for
(
int
?i
=
0
;i
<
files.length;i
++
){
????????????????????TableItem?item
=
new
?TableItem(dropTable,SWT.NONE);
????????????????????item.setText(files[i]);
????????????????}
????????????}
????????}
????}
????
????
public
?
void
?fillTable(){
????????dropTable.setHeaderVisible(
true
);
????????dropTable.setLinesVisible(
true
);
????????
????????TableColumn?partName?
=
new
?TableColumn(dropTable,SWT.LEFT);
????????partName.setResizable(
true
);
????????partName.setText(
"
NAME
"
);
????????partName.setWidth(
250
);
????????
????????TableColumn?employeeName
=
new
?TableColumn(dropTable,SWT.LEFT);
????????employeeName.setResizable(
true
);
????????employeeName.setText(
"
SIZE
"
);
????????employeeName.setWidth(
120
);
????????
????????
for
(
int
?i
=
0
;i
<
10
;i
++
){
????????????TableItem?item
=
new
?TableItem(dropTable,SWT.NONE);
????????????item.setText(
new
?String[]{
"
tableitem
"
+
i,
100
+
i
+
""
});
????????}
????}
????
????
public
?
void
?setFocus(){
????}
}