blog211119. SWT之DnD
DnD过程
Drag and Drop操作用可视化的完成两个widget之间data的传递. 发起方称作drag source, 接收方称作drop target.
一个典型的DnD操作包括,
- 在drag source widget上点压鼠标左键,
- 拖拽鼠标, 即不放开鼠标键的同时, 向drag target移动,
- 移动到drop target widget上释放鼠标键.
1和2是drag, 3是drop.
整个过程中, 可以同时加按键盘ctrl或者shift键决定拖拽要执行的操作种类, 包括
- DND.DROP_COPY, 从source到target复制, cursor提示一个’+’, 加按ctrl.
- DND.DROP_MOVE, 从source到target迁移. 加按shift.
- DND.DROP_LINK, 从source到target建立link, cursor提示一个跳转符号.加按shift+ctrl
- DND.DROP_DEFAULT, 默认的操作种类, 不加按键盘键情形下. 通常由系统决定采用何种操作, 一般是DROP_MOVE.
- DND.DROP_NONE, 提示当前位置下的widget不接受drop, cursor提示为一个禁止符号.
拖拽过程中, 主要通过以下视觉变化提示DnD操作的状态,
- cursor图像
- source widget的外观
- target widget的外观
SWT中用DragSource和DropTarget负责实现DnD功能的实现.
DragSource的DragSourceListener完成source侧的事件处理, 而DropTarget的DropTargetListener负责target侧的事件处理.
DragSourceListener
public interface DragSourceListener extends SWTEventListener
{
public void dragStart(DragSourceEvent event);
public void dragSetData(DragSourceEvent event);
public void dragFinished(DragSourceEvent event);
}
source的3个事件,
- dragStart, 指示用户将发起一个DnD, 一般是用户按压鼠标并拖拽一小距离后触发. 若用户选择取消发起, 则设置 event.doit= false.
- dragSetData, 指示用户提供data, 系统据此要求target判断是否允许该DnD, 以及drop时target使用该data.
- dragFinished, 指示用户DnD结束. 当DnD操作失败时, 例如用户按esc取消或者在不接受DnD的target上drop, event.detail的值是DND.DROP_NONE.
source event sequence有以下几种情形,
- dragStart
- dragStart, dragSetData{0,n}, dragFinished
DropTargetListener
public interface DropTargetListener extends SWTEventListener {
public void dragEnter(DropTargetEvent event);
public void dragLeave(DropTargetEvent event);
public void dragOperationChanged(DropTargetEvent event);
public void dragOver(DropTargetEvent event);
public void drop(DropTargetEvent event);
public void dropAccept(DropTargetEvent event);
}
target的6个事件
- dragEnter, 鼠标移入target时触发. 在此用户可以设置event.detail, 决定操作种类.
- dragLeave, 鼠标移出target或者用户esc取消时触发. 通常用户应在此释放dragEnter中申请的资源.
- dragOperationChanged, DnD操作种类变更时触发, 通常是用户改变键盘按键导致.
- dragOver, 鼠标在target widget上hover时触发. 可以设置event.detail, event.currentType和event.feedback. 而feedback通常用于tree和table中的DnD.
- dropAccept, 触发判断是否接受DnD并进入到下一步drop.
- drop, 成功完成DnD时触发, 用户在此执行读取data和实质动作.
target event sequence有以下几种情形
- dragEnter, dragLeave
- dragEnter, (dragOver | dragOperationChanged){1,n}, dragLeave
- dragEnter, (dragOver | dragOperationChanged){1,n}, dragLeave, dropAccept
- dragEnter, (dragOver | dragOperationChanged){1,n}, dragLeave, dropAccept, drop
典型代码
代码出自eclipse的一篇DnD的介绍, DnD in SWT
import org.eclipse.swt.dnd.*;
// Enable a label as a Drag Source
final Label dragLabel = new Label(shell, SWT.BORDER);
dragLabel.setText("text to be transferred");
// Allow data to be copied or moved from the drag source
int operations = DND.DROP_MOVE | DND.DROP_COPY;
DragSource source = new DragSource(dragLabel, operations);
// Provide data in Text format
Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
source.setTransfer(types);
source.addDragListener(new DragSourceListener() {
public void dragStart(DragSourceEvent event) {
// Only start the drag if there is actually text in the
// label - this text will be what is dropped on the target.
if (dragLabel.getText().length() == 0) {
event.doit = false;
}
}
public void dragSetData(DragSourceEvent event) {
// Provide the data of the requested type.
if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
event.data = dragLabel.getText();
}
}
public void dragFinished(DragSourceEvent event) {
// If a move operation has been performed, remove the data
// from the source
if (event.detail == DND.DROP_MOVE)
dragLabel.setText("");
}
}
});
import org.eclipse.swt.dnd.*;
// Enable a table as a Drop Target
final Table dropTable = new Table(shell, SWT.BORDER);
for (int i = 0; i < 10; i++) {
TableItem item = new TableItem(dropTable, SWT.NONE);
item.setText("item" + I);
}
// Allow data to be copied or moved to the drop target
operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
DropTarget target = new DropTarget(dropTable, operations);
// Receive data in Text or File format
final TextTransfer textTransfer = TextTransfer.getInstance();
final FileTransfer fileTransfer = FileTransfer.getInstance();
types = new Transfer[] {fileTransfer, textTransfer};
target.setTransfer(types);
target.addDropListener(new DropTargetListener() {
public void dragEnter(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
if ((event.operations & DND.DROP_COPY) != 0) {
event.detail = DND.DROP_COPY;
} else {
event.detail = DND.DROP_NONE;
}
}
// will accept text but prefer to have files dropped
for (int i = 0; i < event.dataTypes.length; i++) {
if (fileTransfer.isSupportedType(event.dataTypes[i])){
event.currentDataType = event.dataTypes[i];
// files should only be copied
if (event.detail != DND.DROP_COPY) {
event.detail = DND.DROP_NONE;
}
break;
}
}
}
public void dragOver(DropTargetEvent event) {
event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL;
if (textTransfer.isSupportedType(event.currentDataType)) {
// NOTE: on unsupported platforms this will return null
Object o = textTransfer.nativeToJava(event.currentDataType);
String t = (String)o;
if (t != null) System.out.println(t);
}
}
public void dragOperationChanged(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
if ((event.operations & DND.DROP_COPY) != 0) {
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;
}
}
}
public void dragLeave(DropTargetEvent event) {
}
public void dropAccept(DropTargetEvent event) {
}
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]);
}
}
}
});
驽马一架 2021/11/19