DND入門學習

來源:互聯網
上載者:User

Drag and Drop是Eclipse為使用者在一個或多個SWT應用之間重設組件或資料轉送上提供的簡單快捷的機制。可以使用在普通SWT應用中,也是學習GEF的基礎部分。下面我從以下幾個Drag and Drop所必需的部分來簡單講述:
DragSource And DropTarget
要實現Drag and Drop,就必須要有DragSource And DropTarget。DragSource是資料轉送過程中的資料提供者,而DropTarget是資料接收者。他們分別綁定SWT的widget,需要注意的是同一widget只能幫定在一個DragSource或DropTarget上。在滑鼠拖動的過程中,我們可以通過滑鼠圖形的變化來得知當前經過的是否是一個有效DropTarget,這個過程叫做“drag over effect”。滑鼠圖形同時也可以告訴我們在資料被Drop之後,什麼樣的操作會被執行,是拷貝還是移動還是別的什麼。在windows中有以下幾種滑鼠圖形:
[attachment=453] 
如果我們drag over一個帶有item的組件,比方說tree或者table,那麼item會變成高亮表明我們會將資料Drop在這個item上,這個過程我們叫“drag under effect”。
Transfer
有了DragSource 和 DropTarget之後,我們就需要一個載體來承載不同類型的資料,讓這個載體在DragSource 和 DropTarget之間傳遞資料。Transfer實際上是一個提供資料在Java representation與platform specific representation之間互動的抽象類別.在Java對象與特定的平台之間進行format,下面是幾個format:
TextTransfer String "hello world" 
RTFTransfer String "{//rtf1//b//i hello world}"
FileTransfer String[] new String[] {file1.getAbsolutePath(), file2.getAbsolutePath()}
Transfer是傳輸的載體,TransferData真正的利用JNI將資料和本地作業系統發生關係。TransferData包含了很多特定於平台的公用的屬性,應用不應該直接去訪問這些屬性。如果真的有必要去訪問這些屬性,那麼我們可以通過擴充Transfer類來完成對特定平台的額外操作。
另外,Transfer不只是可以用在DND中,也可以單獨拿出來使用,例如實現Clipboard,可以在copy時將資料暫存於Clipboard中,past時再取出。這個和DND的在Drag時將資料暫存於Clipboard中,Drop時再取出類似。
理解了拖拽的這些概念之後,下面我們就著一個簡單的例子來運用一下。,這個例子中,左面的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(){
    }
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.