× Home Tutorials Training Consulting Products Books Company Donate Contact us









NOW Hiring

Quick links

Share

This tutorial describes the usage of drag and drop in the Eclipse framework. The article assumes that you are familiar with Eclipse plug-in or Eclipse RCP development. This tutorial is based on Eclipse 4.6 (Eclipse Neon).

1. Using drag and drop in SWT

SWT supports drag and drop based on transfer types defined based on the org.eclipse.swt.dnd.Transfer class. Every widget element can define that it provides a certain transfer type as source. It can also define that it accepts a transfer type as destination.

Eclipse provides several pre-defined transfer types. To define your custom transfer type it is recommended to subclass the org.eclipse.swt.dnd.ByteArrayTransfer class.

A drag source is the provider of the drag and drop data as well as the originator of the drag and drop operation. A drop target receives data in a drag and drop operation. The drop target receives the data provided by the drag source. it can be another location in the same widget, a different widget, or a different application. For example, you can drag text from your application and drop it on an email application, or you could drag an item in a tree and drop it below a different node in the same tree.

The following demonstrates how to provide text data from a label.

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.*;
2
3        // Enable a table as a Drop Target
4        final Table dropTable = new Table(shell, SWT.BORDER);
5        for (int i = 0; i < 10; i++) {
6            TableItem item = new TableItem(dropTable, SWT.NONE);
7            item.setText("item" + I);
8        }
9
10        // Allow data to be copied or moved to the drop target
11        operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
12        DropTarget target = new DropTarget(dropTable, operations);
13
14        // Receive data in Text or File format
15        final TextTransfer textTransfer = TextTransfer.getInstance();
16        final FileTransfer fileTransfer = FileTransfer.getInstance();
17        types = new Transfer[] {fileTransfer, textTransfer};
18        target.setTransfer(types);
19
20        target.addDropListener(new DropTargetListener() {
21          public void dragEnter(DropTargetEvent event) {
22             if (event.detail == DND.DROP_DEFAULT) {
23                 if ((event.operations & DND.DROP_COPY) != 0) {
24                     event.detail = DND.DROP_COPY;
25                 } else {
26                     event.detail = DND.DROP_NONE;
27                 }
28             }
29             // will accept text but prefer to have files dropped
30             for (int i = 0; i < event.dataTypes.length; i++) {
31                 if (fileTransfer.isSupportedType(event.dataTypes[i])){
32                     event.currentDataType = event.dataTypes[i];
33                     // files should only be copied
34                     if (event.detail != DND.DROP_COPY) {
35                         event.detail = DND.DROP_NONE;
36                     }
37                     break;
38                 }
39             }
40           }
41           public void dragOver(DropTargetEvent event) {
42                event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL;
43                if (textTransfer.isSupportedType(event.currentDataType)) {
44                    // NOTE: on unsupported platforms this will return null
45                    Object o = textTransfer.nativeToJava(event.currentDataType);
46                    String t = (String)o;
47                    if (t != null) System.out.println(t);
48                }
50            }
51            public void dragOperationChanged(DropTargetEvent event) {
52                if (event.detail == DND.DROP_DEFAULT) {
53                    if ((event.operations & DND.DROP_COPY) != 0) {
54                        event.detail = DND.DROP_COPY;
55                    } else {
56                        event.detail = DND.DROP_NONE;
57                    }
58                }
59                // allow text to be moved but files should only be copied
60                if (fileTransfer.isSupportedType(event.currentDataType)){
61                    if (event.detail != DND.DROP_COPY) {
62                        event.detail = DND.DROP_NONE;
63                    }
64                }
65            }
66            public void dragLeave(DropTargetEvent event) {
67            }
68            public void dropAccept(DropTargetEvent event) {
69            }
70            public void drop(DropTargetEvent event) {
71                if (textTransfer.isSupportedType(event.currentDataType)) {
72                    String text = (String)event.data;
73                    TableItem item = new TableItem(dropTable, SWT.NONE);
74                    item.setText(text);
75                }
76                if (fileTransfer.isSupportedType(event.currentDataType)){
77                    String[] files = (String[])event.data;
78                    for (int i = 0; i < files.length; i++) {
79                        TableItem item = new TableItem(dropTable, SWT.NONE);
80                        item.setText(files[i]);
81                    }
82                }
83            }
84        });

2. Exercise: Drag and Drop in SWT

Create the following class.

package de.vogella.swt.dnd;

import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import de.vogella.swt.dnd.MyDragSourceListener;
import de.vogella.swt.dnd.MyDropTargetListener;

public class PhotoShuffler {

    public static void main(String[] args) {

        // setup the SWT window
        Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setSize(520, 200);
        shell.setLayout(new RowLayout());
        shell.setText("Photo Shuffler");

        // initialize a parent composite with a grid layout manager
        // since the demo application uses 4x pictures the grid has exactly
        // 4x columns
        Composite parent = new Composite(shell, SWT.NONE);
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 4;
        parent.setLayout(gridLayout);

        // determine the path where the pictures are stored
        String path = System.getProperty("user.dir") + "/images/";
        // initialize an array with the photograph names
        String[] imgNames = new String[] { "lars.png", "andre.png",
                "matthias.png", "arne.png" };

        // loop over the photo array and establish all listeners
        for (int i = 0; i < imgNames.length; i++) {
            // labels serve as containers for the images
            Label label = new Label(parent, SWT.NONE);
            Image img = new Image(display, path + imgNames[i]);
            label.setImage(img);

            // enable each label to be draggable
            DragSource source = new DragSource(label, DND.DROP_NONE);
            source.setTransfer(new Transfer[] { TextTransfer.getInstance() });
            // add a drag listener
            source.addDragListener(new MyDragSourceListener(parent, source));

            // enable each label to be a drop target
            DropTarget target = new DropTarget(label, DND.DROP_NONE);
            target.setTransfer(new Transfer[] { TextTransfer.getInstance() });
            // add a drop listener
            target.addDropListener(new MyDropTargetListener(parent, target));
        }

        // show the SWT window
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        // tear down the SWT window
        display.dispose();
    }
}

Create the following DragSource and DragTarget Listener.

package de.vogella.swt.dnd;

import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

public class MyDropTargetListener implements DropTargetListener {

    private Composite parentComposite;
    private DropTarget target;

    /**
     * @param parentComposite
     *            - the composite that holds all pictures
     * @param target
     *            - the drop target
     */
    public MyDropTargetListener(Composite parentComposite, DropTarget target) {
        this.parentComposite = parentComposite;
        this.target = target;
    }

    public void dragEnter(DropTargetEvent event) {
    }

    public void dragOver(DropTargetEvent event) {
    }

    public void dragLeave(DropTargetEvent event) {
    }

    public void dropAccept(DropTargetEvent event) {
    }

    public void dragOperationChanged(DropTargetEvent event) {
    }

    /**
     * This method moves the dragged picture to the new position and shifts the
     * old picture to the right or left.
     */
    public void drop(DropTargetEvent event) {

        // retrieve the stored index
        int sourceIndex = Integer.valueOf(event.data.toString());

        // compute the index of target control
        Control targetControl = target.getControl();
        int targetIndex = -1;
        for (int i = 0; i < parentComposite.getChildren().length; i++) {
            if (parentComposite.getChildren()[i].equals(targetControl)) {
                targetIndex = i;
                break;
            }
        }

        Control sourceControl = parentComposite.getChildren()[sourceIndex];
        // do not do anything if the dragged photo is dropped at the same
        // position
        if (targetIndex == sourceIndex)
            return;

        // if dragged from left to right
        // shift the old picture to the left
        if (targetIndex > sourceIndex)
            sourceControl.moveBelow(targetControl);
        // if dragged from right to left
        // shift the old picture to the right
        else
            sourceControl.moveAbove(targetControl);

        // repaint the parent composite
        parentComposite.layout();
    }

}
package de.vogella.swt.dnd;

import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.widgets.Composite;

public class MyDragSourceListener implements DragSourceListener {

    private Composite parentComposite;
    private DragSource source;

    /**
     * @param parentComposite
     *            - the composite that holds all pictures
     * @param source
     *            - the drag source
     *
     */
    public MyDragSourceListener(Composite parentComposite, DragSource source) {
        this.parentComposite = parentComposite;
        this.source = source;
    }

    public void dragStart(DragSourceEvent event) {
    }

    public void dragFinished(DragSourceEvent event) {
    }

    /**
     * The method computes the position / index of the source control (label) in
     * the children array of the parent composite. This index is passed to the
     * drop target using the data field of the drag source event.
     */
    public void dragSetData(DragSourceEvent event) {
        for (int i = 0; i < parentComposite.getChildren().length; i++) {
            if (parentComposite.getChildren()[i].equals(source.getControl())) {
                event.data = new Integer(i).toString();
                break;
            }
        }
    }

}

3. Exercise: Implement drag and drop

The following exercise demonstrates the usage of drag and drop for customer domain objects and SWT widgets. You will drag and drop between two JFace viewers (a table and a tree).

3.1. Create new project

Create a new Eclipse RCP application called com.vogella.dnd.jface with two views.

Create the following model class.

package de.vogella.swt.dnd;

import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.widgets.Composite;

public class MyDragSourceListener implements DragSourceListener {

    private Composite parentComposite;
    private DragSource source;

    /**
     * @param parentComposite
     *            - the composite that holds all pictures
     * @param source
     *            - the drag source
     *
     */
    public MyDragSourceListener(Composite parentComposite, DragSource source) {
        this.parentComposite = parentComposite;
        this.source = source;
    }

    public void dragStart(DragSourceEvent event) {
    }

    public void dragFinished(DragSourceEvent event) {
    }

    /**
     * The method computes the position / index of the source control (label) in
     * the children array of the parent composite. This index is passed to the
     * drop target using the data field of the drag source event.
     */
    public void dragSetData(DragSourceEvent event) {
        for (int i = 0; i < parentComposite.getChildren().length; i++) {
            if (parentComposite.getChildren()[i].equals(source.getControl())) {
                event.data = new Integer(i).toString();
                break;
            }
        }
    }

}
package com.vogella.dnd.jface.model;

public class Todo {
        private String shortDescription;
        private String longDescription;

        public Todo(String shortDescription, String longDescription) {
                this.shortDescription = shortDescription;
                this.longDescription = longDescription;
        }

        public String getShortDescription() {
                return shortDescription;
        }
        public void setShortDescription(String shortDescription) {
                this.shortDescription = shortDescription;
        }
        public String getLongDescription() {
                return longDescription;
        }
        public void setLongDescription(String longDescription) {
                this.longDescription = longDescription;
        }


}

Create the following content providers (Singletons).

package com.vogella.dnd.jface.model;

import java.util.ArrayList;
import java.util.List;

public enum ContentProvider {
        INSTANCE;

        public List<Todo> getModel(){
                List<Todo> list = new ArrayList<Todo>();
                Todo todo = new Todo("Java", "Learn the Closure proposal");
                list.add(todo);
                todo = new Todo("Eclipse", "Learn more about the RCP platform");
                list.add(todo);
                return list;
        }
}
package com.vogella.dnd.jface.model;

import java.util.ArrayList;
import java.util.List;

public enum ContentProviderTree {
        INSTANCE;
        List<String> list = new ArrayList<String>();

        private ContentProviderTree() {
                list.add("Branch1");
                list.add("Branch1");
        }

        public List<String> getModel(){
                return list;
        }
}

Create the following label and content provider for your JFace viewers.

package com.vogella.dnd.jface.viewers;

import java.util.List;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

import com.vogella.dnd.jface.model.Todo;

public class TableContentProvider implements IStructuredContentProvider {

        @Override
        public Object[] getElements(Object inputElement) {
                List<Todo> list = (List<Todo>) inputElement;
                return list.toArray();
        }

}
package com.vogella.dnd.jface.viewers;

import java.util.List;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class TreeContentProvider implements ITreeContentProvider {

        @Override
        public Object[] getChildren(Object parentElement) {
                return null;
        }

        @Override
        public Object getParent(Object element) {
                return null;
        }

        @Override
        public boolean hasChildren(Object element) {
                return false;
        }

        @Override
        public Object[] getElements(Object inputElement) {
                List<String> list = (List<String>) inputElement;
                return list.toArray();
        }
}
package com.vogella.dnd.jface.viewers;

import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.swt.graphics.Image;

import com.vogella.dnd.jface.model.Todo;

public class TableLabelProvider extends BaseLabelProvider implements
                ITableLabelProvider {

        @Override
        public Image getColumnImage(Object element, int columnIndex) {
                return null;
        }

        @Override
        public String getColumnText(Object element, int columnIndex) {
                Todo todo = (Todo) element;
                switch (columnIndex) {
                case 0:
                        return todo.getShortDescription();
                case 1:
                        return todo.getLongDescription();
                }
                return "Not supported";
        }

}
package com.vogella.dnd.jface.viewers;

import org.eclipse.jface.viewers.LabelProvider;


public class TreeLabelProvider extends LabelProvider {
        @Override
        public String getText(Object element) {
                String s = (String) element;
                return s;
        }

}

3.2. Drag and drop Listener

Create the following drag and drop listener. These are later assigned to your table and tree widgets.

package com.vogella.dnd.jface.dnd;

import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.TextTransfer;

import com.vogella.dnd.jface.model.Todo;
public class MyDragListener implements DragSourceListener {

        private final TableViewer viewer;

        public MyDragListener(TableViewer viewer) {
                this.viewer = viewer;
        }

        @Override
        public void dragFinished(DragSourceEvent event) {
                System.out.println("Finshed Drag");
        }

        @Override
        public void dragSetData(DragSourceEvent event) {
                // Here you do the convertion to the type which is expected.
                IStructuredSelection selection = viewer.getStructuredSelection();
                Todo firstElement = (Todo) selection.getFirstElement();

                if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
                        event.data = firstElement.getShortDescription() + " " + firstElement.getLongDescription();
                }

        }

        @Override
        public void dragStart(DragSourceEvent event) {
                System.out.println("Start Drag");
        }

}
package com.vogella.dnd.jface.dnd;

import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TransferData;

import com.vogella.dnd.jface.model.ContentProviderTree;

public class MyDropListener extends ViewerDropAdapter {

        private final Viewer viewer;

        public MyDropListener(Viewer viewer) {
                super(viewer);
                this.viewer = viewer;
        }

        @Override
        public void drop(DropTargetEvent event) {
                int location = this.determineLocation(event);
                String target = (String) determineTarget(event);
                String translatedLocation ="";
                switch (location){
                case 1 :
                        translatedLocation = "Dropped before the target ";
                        break;
                case 2 :
                        translatedLocation = "Dropped after the target ";
                        break;
                case 3 :
                        translatedLocation = "Dropped on the target ";
                        break;
                case 4 :
                        translatedLocation = "Dropped into nothing ";
                        break;
                }
                System.out.println(translatedLocation);
                System.out.println("The drop was done on the element: " + target );
                super.drop(event);
        }

        // This method performs the actual drop
        // We simply add the String we receive to the model and trigger a refresh of the
        // viewer by calling its setInput method.
        @Override
        public boolean performDrop(Object data) {
                ContentProviderTree.INSTANCE.getModel().add( data.toString());
                viewer.setInput(ContentProviderTree.INSTANCE.getModel());
                return false;
        }

        @Override
        public boolean validateDrop(Object target, int operation,
                        TransferData transferType) {
                return true;

        }



}

3.3. Adjusting your parts

Adjust your views. The first view shows a table and allows the user to drag an elements from it. The second view accepts drops.

package com.vogella.dnd.jface.view;

import javax.annotation.PostConstruct;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;

import com.vogella.dnd.jface.dnd.MyDragListener;
import com.vogella.dnd.jface.model.ContentProvider;
import com.vogella.dnd.jface.viewers.TableContentProvider;
import com.vogella.dnd.jface.viewers.TableLabelProvider;

public class TableView {


        @PostConstruct
        public void createPartControl(Composite parent) {
                TableViewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
                                | SWT.V_SCROLL);
                int operations = DND.DROP_COPY| DND.DROP_MOVE;
                Transfer[] transferTypes = new Transfer[]{TextTransfer.getInstance()};
                viewer.addDragSupport(operations, transferTypes , new MyDragListener(viewer));
                viewer.setContentProvider(new TableContentProvider());
                viewer.setLabelProvider(new TableLabelProvider());
                viewer.setInput(ContentProvider.INSTANCE.getModel());
        }
}
package com.vogella.dnd.jface.view;

import javax.annotation.PostConstruct;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

import com.vogella.dnd.jface.dnd.MyDropListener;
import com.vogella.dnd.jface.model.ContentProviderTree;
import com.vogella.dnd.jface.viewers.TreeContentProvider;
import com.vogella.dnd.jface.viewers.TreeLabelProvider;

public class TreeView  {

        @PostConstruct
        public void createPartControl(Composite parent) {
                TreeViewer viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
                                | SWT.V_SCROLL);
                int operations = DND.DROP_COPY | DND.DROP_MOVE;
                Transfer[] transferTypes = new Transfer[]{TextTransfer.getInstance()};
                viewer.addDropSupport(operations, transferTypes, new MyDropListener(viewer));
                viewer.setContentProvider(new TreeContentProvider());
                viewer.setLabelProvider(new TreeLabelProvider());
                viewer.setInput(ContentProviderTree.INSTANCE.getModel());
        }
}

4. About this website

5. Eclipse drag and drop resources

5.1. vogella GmbH training and consulting support

TRAINING SERVICE & SUPPORT

The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”.

The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers.

Copyright © 2012-2016 vogella GmbH. Free use of the software examples is granted under the terms of the EPL License. This tutorial is published under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany license.

See Licence.