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 SWT and Eclipse plug-in or Eclipse RCP development.

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

The methods moveAbove and moveBelow provide the option to re-arrange widgets within a layout. The following example demonstrates the usage of drag and drop to re-arrange widgets in a layout. It assumes that you have created several png file in an images folder of the project.

Create the following class.

package com.vogella.swt.widgets.dnd;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class PhotoShuffler {

        public static void main(String[] args) {
                // setup the SWT window
                Display display = new Display();
                final Shell shell = new Shell(display);
                shell.setLayout(new FillLayout());
                shell.setText("Photo Shuffler");

                // initialize a parent composite with a grid layout manager
                Composite parent = new Composite(shell, SWT.NONE);
                GridLayout gridLayout = new GridLayout();
                gridLayout.numColumns = 2;
                gridLayout.marginWidth=20;
                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

                File imageDir= new File(path);

                // loop over the photo array and establish all listeners
                List<File> files = Arrays.stream(imageDir.listFiles())
                                                 .filter(f -> f.isFile() && f.getName().endsWith(".png"))
                                                .collect(Collectors.toList());

                for (File file : files) {
                        // labels serve as containers for the images
                        Label label = new Label(parent, SWT.NONE);
                        Image img = new Image(display,file.getAbsolutePath());
                        label.setImage(img);

                        // enable each label to be draggable
                        DragSource source = new DragSource(label, DND.DROP_NONE);
                        source.setTransfer(TextTransfer.getInstance()); // varargs are supported as of 4.7
                        // 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() }); // varargs are not yet supported see https://git.eclipse.org/r/#/c/92236                        // add a drop listener
                        target.addDropListener(new MyDropTargetListener(parent, target));
                }

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

        private static class MyDragSourceListener extends DragSourceAdapter {

                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;
                }

                /**
                 * 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;
                                }
                        }
                }

        }


public static class MyDropTargetListener extends DropTargetAdapter {

    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;
    }

    /**
     * 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.requestLayout();
    }

}


}
photodnd

3. Exercise: Implement drag and drop

The following exercise demonstrates the usage of drag and drop for customer domain objects and SWT widgets. You 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 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.