理解了拖拽的这些概念之后,下面我们就着一个简单的例子来运用一下。如图所示,这个例子中,左面的tree是DragSource,右面的table是DropTarget,我们从左面的tree中选择一条,拖进右边的table中:
我们先从DragSource开始:
//获得一个TextTransfer的实例,TextTransfer是Transfer的一个子类,
//他提供将普通文本以Java String的表示转换为特定于平台的表示的机制。
TextTransfer textTransfer=TextTransfer.getInstance();
//构造一个普通的tree
dragTree=new Tree(parent,SWT.FULL_SELECTION|SWT.SINGLE);
//将dragTree与DragSource绑定(一个widget只能绑定在一个DragSource),
//并允许数据可以从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个方法:
// 指定拖动开始的执行策略。
public void dragStart(DragSourceEvent event){
//在这里可以设置一些条件,如果不符合条件,比方说选中的treeitem是根,
//则不可拖动
if(treeitem是根){
event.doit=false;
}
}
//dragSetData方法在dragStart通过之后才被调用。这个方法可能会因为同一种传输
//类型多次set或不同的多种传输类型的set而被多次调用,象windows等有些平台
//中,dropTarget可以在鼠标移动的过程中请求数据,但是在Motif等平台中,只可以
//在drop操作完成之后才可以请求数据,所以在这个方法中不要假设drag and drop操
//作已经完成.在这个方法中是无法知道data将被drop到哪里.
//set的Data也要符合指定的Transfer的format类型。
public void dragSetData(DragSourceEvent event){
//在这里可以为DragSourceEvent添加数据,这个方法在拖动过程中
//会被不停的调用
TreeItem selection = DragAndDrop.this.dragTree.getSelection()[0];
event.data=selection.getText();
}
// 根据事先指定好的操作类型来处理操作结果
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的范围内时被调用。
public void dragEnter(DropTargetEvent event){
//在dragEnter中应用可以定义default operation.如果一个drop target在创建的时候被指定为
//带有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对象形式表现,
//event.dataTypes 是drag source支持的所有类型的列表,以TransferData数组形式表现,
//我们可以将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时会被重复不停的调用.
//如果光标是静止的,dragOver event依然会有规则的按一定时间间隔被调用.
//这个方法一般在drop target是table或tree时用得比较多,可以根据不同的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事件发生。
//辅助按键可以改变即将进行的操作。例如:
//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事件发生. 如果你在dragEnter中分配了一些资源,
//就应该在dragLeave中释放.dragLeave事件在用户通过Escape键取消Drag and Drop操作时也会发生
//刚好在drop操作被执行之前.
public void dragLeave(DropTargetEvent event){
}
//dropAccept事件为应用提供了最后一次定义数据类型的机会,定义的数据类型将被返回到drop事件.
//这些是通过向event.currentDataType赋event.dataTypes中的值来实现的.
public void dropAccept(DropTargetEvent event){
}
//如果在之前的事件中得到了有效的操作和currentDataType,那么当用户在drop target上松开鼠标时,drop事件会发生。
//event.data属性包含了请求到的数据,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是一个可以提供数据在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),
//
并允许数据可以从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{
//
指定拖动开始的执行策略。
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通过之后才被调用。这个方法可能会因为同一种传输类型多次set或
//
不同的多种传输类型的set而被多次调用,象windows等有些平台中,dropTarget可以在鼠标移动的
//
过程中请求数据,但是在Motif等平台中,只可以在drop操作完成之后才可以请求数据,所以在这个方
//
法中不要假设drag and drop操作已经完成.在这个方法中是无法知道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();
}
}
}
//
根据事先指定好的操作类型来处理操作结果
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的范围内时被调用。
public
void
dragEnter(DropTargetEvent event){
//
在dragEnter中应用可以定义default operation.如果一个drop target在创建的时候被指定为
//
带有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对象形式表现,
//
event.dataTypes 是drag source支持的所有类型的列表,以TransferData数组形式表现,
//
我们可以将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时会被重复不停的调用.
//
如果光标是静止的,dragOver event依然会有规则的按一定时间间隔被调用.
//
这个方法一般在drop target是table或tree时用得比较多,可以根据不同的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事件发生。
//
辅助按键可以改变即将进行的操作。例如:
//
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事件发生. 如果你在dragEnter中分配了一些资源,
//
就应该在dragLeave中释放.dragLeave事件在用户通过Escape键取消Drag and Drop操作时也会发生
//
刚好在drop操作被执行之前.
public
void
dragLeave(DropTargetEvent event){
}
//
dropAccept事件为应用提供了最后一次定义数据类型的机会,定义的数据类型将被返回到drop事件.
//
这些是通过向event.currentDataType赋event.dataTypes中的值来实现的.
public
void
dropAccept(DropTargetEvent event){
}
//
如果在之前的事件中得到了有效的操作和currentDataType,那么当用户在drop target上松开鼠标时,drop事件会发生。
//
event.data属性包含了请求到的数据,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(){
}
}