作業系統中最常用的拖拽功能就是檔案的移動複制,拖 拽功能提高了軟體的簡用性。SWT也支援拖拽功能,不過程式設計實作比較繁瑣。圖18.1是實作拖拽的示意圖,它首先要設定好拖拽源(DragSource) 和能夠接收的目标地(DropTarget),然後再設定一個運送拖拽資料的載體(Transfer),最後最繁瑣的就是要給DragSource和 DropTarget分别添加拖拽監聽器,并根據拖拽途中的各種情況實作監聽器的各方法。
圖18.1 SWT拖拽實作的示意圖 圖18.2 拖拽執行個體一
下面給出一個拖拽執行個體,其運作效果如圖18.2所示。圖的左邊是一個按鈕,右邊是一個文本框,可以将按鈕文字拖拽到文本框中。如果按住Shift鍵拖拽,則為移動文字,結果是按鈕變成空白,文字移到文本框。具體實作代碼如下:
public class DragAndDrop1 {
private TextTransfer textTransfer = TextTransfer.getInstance ();
private Button sourceText;
private Text targetText;
public static void main(String[] args) {
new DragAndDrop1().open();
}
private void open() {
final Display display = Display.getDefault ();
final Shell shell = new Shell();
shell.setSize(300, 100);
// ---------建立視窗中的其他界面元件-------------
// 建立視窗元件
shell.setLayout(new FillLayout());
sourceText = new Button(shell, SWT.NONE );
sourceText.setText("HelloWolrd");
new Label(shell, SWT.NONE );// 分隔區
targetText = new Text(shell, SWT.BORDER );
// --------- 拖動設定-----------------
// 設定sourceText為拖拽源。允許資料被移動或複制
DragSource source = new DragSource(sourceText, DND.DROP_MOVE | DND.DROP_COPY );
source.setTransfer(new Transfer[] { textTransfer });// 設定傳輸載體為文本型
source.addDragListener(new MyDragSourceListener());
// 設定targetText為目标地
DropTarget target = new DropTarget(targetText, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT );
target.setTransfer(new Transfer[] { textTransfer });
target.addDropListener(new MyDropTargetListener());
// -----------------END------------------------
shell.layout();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private class MyDragSourceListener implements DragSourceListener {
// 判斷是否允許拖拽。這裡設定空字串時不允許拖拽
public void dragStart(DragSourceEvent event) {
Button button = getSource(event);// getSource是自定義方法
if (button.getText().trim().equals(""))
event.doit = false;
}
// 自定義方法,取得拖拽源元件
private Button getSource(DragSourceEvent event) {
DragSource source = (DragSource) event.widget;
Button button = (Button) source.getControl();// 即sourceButton
return button;
}
// 設定需要用Transfer傳輸的資料
public void dragSetData(DragSourceEvent event) {
if (textTransfer.isSupportedType(event.dataType)) {// 是否支援拖拽的資料類型
Button button = getSource(event);
event.data = button.getText();
}
}
// 拖拽操作完成後執行此方法
public void dragFinished(DragSourceEvent event) {
if (event.detail == DND.DROP_MOVE ) {// 如果是移動則删除sourceText中的文字
Button button = getSource(event);
button.setText("");
}
}
}
private class MyDropTargetListener implements DropTargetListener {
// 滑鼠進入目标元件時調用此方法
public void dragEnter(DropTargetEvent event) {
// 預設為DND.DROP_DEFAULT,這裡将其設為複制;按住Ctrl鍵為DND.DROP_COPY;按住Shift鍵為DND.DROP_MOVE。
if (event.detail == DND.DROP_DEFAULT )
event.detail = DND.DROP_COPY ;
}
// 滑鼠在目标元件範圍時會不斷調用此方法。在此方法中主要是設定event.feedback,其可能值有:
//FEEDBACK_EXPAND 使目前光标下的項展開,以便拖拽到子項上,僅用于樹型元件。
//FEEDBACK_INSERT_AFTER 在某項處于光标下之後顯示一個插入标記,僅用于表格和樹。
//FEEDBACK_INSERT_BEFORE 在某項處于目前光标下之前顯示一個插入标記,僅用于表格和樹。
//FEEDBACK_NONE 什麼也不做.
//FEEDBACK_SCROLL 使目标元件可以滾動,以便可以拖到目前看不見的項上,僅用于表格和樹。
//FEEDBACK_SELECT 使目前光标下的項被選中,僅用于表格和樹。
public void dragOver(DropTargetEvent event) {
event.feedback = DND.FEEDBACK_NONE ;
}
// 當按下或放開輔助按鍵(如Ctrl, Shift)時調用此方法
public void dragOperationChanged(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT )
event.detail = DND.DROP_COPY ;
}
// 當滑鼠離開目标元件時會調用此方法
public void dragLeave(DropTargetEvent event) {}
// 在完成拖拽操作,執行drop方法之前調用此方法。
public void dropAccept(DropTargetEvent event) {}
// 在完成拖拽操作時最後調用的方法
public void drop(DropTargetEvent event) {
if (textTransfer.isSupportedType(event.currentDataType)) {
String str = (String) event .data;// 取出傳輸資料
DropTarget target = (DropTarget) event.widget;
Text text = (Text) target.getControl();// 即targetText
text.setText(str);
}
}
}
}
程式說明:
● 雖然拖拽常用于表格和樹,而本節是用按鈕和文本框做執行個體,但基本原理和代碼結構都一樣。
● 可以設定多個拖拽目标地。一個元件既可以是拖拽源,也可以是拖拽目标地。
● event.detail= DND.DROP_NONE可以使拖拽失效。
● TextTransfer是Transfer的子類,檢視Transfer的類層次結構可以找到更多的拖拽傳輸載體。