GWT Drag and Drop Example
In this example we will learn about GWT Drag and Drop. The Google Web Toolkit is a development framework for creating Ajax-enabled web applications in Java. Drag and Drop is supported in most browsers but currently it’s not supported in Opera. Tools and technologies used in this example are Java 1.8, Eclipse Luna 4.4.2, Eclipse GWT Plugin 2.6
1. Introduction
The ultimate in user interactivity, drag and drop is taken for granted in desktop applications but is a litmus test of sorts for web applications. Until now, drag and drop for web applications has, for the most part, been limited to specialized JavaScript frameworks such as Script.aculo.us and Rico. With the advent of GWT, we have drag-and-drop capabilities in a Java-based web application framework. Although GWT does not explicitly support drag and drop (drag and drop is an anticipated feature in the future), it provides us with all the necessary ingredients to make our own drag-and-drop module.
Whatever we are dragging we can make that appear beneath the cursor and it’s easy to do that. So the key elements are draggable things, drop targets and tons of events in between.
2. Configuration
Below is the GWT configuration file. The most important part is the entry point class which is defined in this configuration file.
GWTDradAndDrop.gwt.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.6.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.6.0/distro-source/core/src/gwt-module.dtd"> <module rename-to='gwtdradanddrop'> <!-- Inherit the core Web Toolkit stuff. --> <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.user.theme.clean.Clean'/> <!-- Specify the app entry point class. --> <entry-point class='com.javacodegeeks.client.GWTDradAndDrop'/> <!-- Specify the paths for translatable code --> <source path='client'/> <source path='shared'/> </module>
3. Java files
To make a widget draggable, you must set the draggable property and add a drag handler. getElement().setDraggable(Element.DRAGGABLE_TRUE);
The allowed values are DRAGGABLE_AUTO (auto), DRAGGABLE_FALSE (false), DRAGGABLE_TRUE (true).
Some widgets support the draggable property directly and some don’t. Label doesn’t. In the Drag Start Handler, you must set the event data, or some browsers will not allow you to drag it.
To make a widget droppable, you must add a DragOver handler and a drop handler. Make sure to call event.preventDefault()
in the onDrop, or else the browser might navigate away from the current page!
private void initDrag() { getElement().setDraggable(Element.DRAGGABLE_TRUE); addDragStartHandler(new DragStartHandler() { @Override public void onDragStart(DragStartEvent event) { // Remember what's being dragged dragging = DragDropLabel.this; event.setData("ID", "UniqueIdentifier"); event.getDataTransfer().setDragImage(getElement(), 10, 10); } }); }
We need to call the setData()
for some of the browsers like Firefox. It sets the data in the DataTransfer object for the specified format. event.getDataTransfer().setDragImage(getElement(), 10, 10);
copies the label image for the drag icon. The 10, 10 indicate the ‘x’ and ‘y’ offset of the cursor.
We don’t need to use the DragOverHandler but we need to add it. Here we are just changing the style.
addDomHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { addStyleName("dropping"); } }, DragOverEvent.getType());
To prevent the native text drop do event.preventDefault();
DragDropLabel.java
package com.javacodegeeks.client; import java.util.ArrayList; import java.util.List; import com.google.gwt.event.dom.client.DragLeaveEvent; import com.google.gwt.event.dom.client.DragLeaveHandler; import com.google.gwt.event.dom.client.DragOverEvent; import com.google.gwt.event.dom.client.DragOverHandler; import com.google.gwt.event.dom.client.DragStartEvent; import com.google.gwt.event.dom.client.DragStartHandler; import com.google.gwt.event.dom.client.DropEvent; import com.google.gwt.event.dom.client.DropHandler; import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Tree; import com.google.gwt.user.client.ui.TreeItem; import com.google.gwt.user.client.ui.Widget; public class DragDropLabel extends Label { private static DragDropLabel dragging = null; final boolean droppable; public DragDropLabel(String text, boolean draggable, boolean droppable) { super(text); if (draggable) { initDrag(); } if (droppable) { initDrop(); } this.droppable = droppable; if (droppable) { addStyleName("droppable"); } else if (draggable) { addStyleName("draggable"); } } private void initDrag() { getElement().setDraggable(Element.DRAGGABLE_TRUE); addDragStartHandler(new DragStartHandler() { @Override public void onDragStart(DragStartEvent event) { dragging = DragDropLabel.this; event.setData("ID", "UniqueIdentifier"); event.getDataTransfer().setDragImage(getElement(), 10, 10); } }); } private void initDrop() { addDomHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { addStyleName("dropping"); } }, DragOverEvent.getType()); addDomHandler(new DragLeaveHandler() { @Override public void onDragLeave(DragLeaveEvent event) { removeStyleName("dropping"); } }, DragLeaveEvent.getType()); addDomHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { event.preventDefault(); if (dragging != null) { TreeItem target = null; TreeItem source = null; Tree tree = (Tree) DragDropLabel.this.getParent(); List<TreeItem> treeItems = new ArrayList<TreeItem>(); treeItems.add(tree.getItem(0)); while (!treeItems.isEmpty()) { TreeItem item = treeItems.remove(0); for (int i = 0; i < item.getChildCount(); i++) { treeItems.add(item.getChild(i)); } Widget widget = item.getWidget(); if (widget != null) { if (widget == dragging) { source = item; if (target != null) { break; } } if (widget == DragDropLabel.this) { target = item; widget.removeStyleName("dropping"); if (source != null) { break; } } } } if (source != null && target != null) { TreeItem testTarget = target; while (testTarget != null) { if (testTarget == source) { return; } testTarget = testTarget.getParentItem(); } target.addItem(source); target.setState(true); } dragging = null; } } }, DropEvent.getType()); } }
GWTDradAndDrop.java
package com.javacodegeeks.client; import java.util.ArrayList; import java.util.List; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.Random; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Tree; import com.google.gwt.user.client.ui.TreeItem; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class GWTDradAndDrop implements EntryPoint { /** * This is the entry point method. */ public void onModuleLoad() { Tree tree = new Tree(); TreeItem root = new TreeItem(new DragDropLabel("Grand Parent", false, true)); tree.addItem(root); root.addItem(new DragDropLabel("Parent 1", true, true)); root.addItem(new DragDropLabel("Parent 2", true, true)); TreeItem parent3 = root.addItem(new DragDropLabel("Parent 3", true, true)); parent3.addItem(new DragDropLabel("Parent 3.1", true, true)); parent3.addItem(new DragDropLabel("Parent 3.2", true, true)); List<TreeItem> treeItems = new ArrayList<TreeItem>(); treeItems.add(tree.getItem(0)); int number = 1; while (!treeItems.isEmpty()) { TreeItem item = treeItems.remove(0); for (int i = 0; i < item.getChildCount(); i++) { treeItems.add(item.getChild(i)); } int files = Random.nextInt(4) + 1; for (int j = 0; j < files; j++) { item.addItem(new TreeItem(new DragDropLabel("Child " + number, true, false))); number++; } item.setState(true); } RootPanel.get().add(tree); } }
4. GWT Compile
To compile the application right click on the project and choose ‘Google’. Then choose ‘GWT Compile’.
After clicking on the ‘GWT Compile’ we will get the below screen.
Click on the compile button. GWT will start compiling the project. You will see the below logs in the ‘Console’ window.
Compiling module com.javacodegeeks.GWTDradAndDrop Compiling 5 permutations Compiling permutation 0... Compiling permutation 1... Compiling permutation 2... Compiling permutation 3... Compiling permutation 4... Compile of permutations succeeded Linking into E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\gwtdradanddrop Link succeeded Compilation succeeded -- 74.734s
5. Running the application
To run the application right click on the project and choose ‘Run As’ -> ‘Web Application (GWT Classic Dev Mode)’. Below is the screenshot:
You will get below logs in the ‘Console’ window. If there is any exception, it will be displayed in the same window.
Initializing App Engine server Sep 01, 2015 9:17:02 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml INFO: Successfully processed E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\WEB-INF/appengine-web.xml Sep 01, 2015 9:17:02 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml INFO: Successfully processed E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\WEB-INF/web.xml Sep 01, 2015 9:17:02 PM com.google.appengine.tools.development.SystemPropertiesManager setSystemProperties INFO: Overwriting system property key 'java.util.logging.config.file', value 'E:\meraj\study\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.9.19\appengine-java-sdk-1.9.19\config\sdk\logging.properties' with value 'WEB-INF/logging.properties' from 'E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\WEB-INF\appengine-web.xml' Sep 01, 2015 9:17:02 PM com.google.apphosting.utils.jetty.JettyLogger info INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger Sep 01, 2015 9:17:03 PM com.google.appengine.tools.development.DevAppServerImpl setServerTimeZone WARNING: Unable to set the TimeZone to UTC (this is expected if running on JDK 8) Sep 01, 2015 9:17:03 PM com.google.apphosting.utils.jetty.JettyLogger info INFO: jetty-6.1.x Sep 01, 2015 9:17:07 PM com.google.apphosting.utils.jetty.JettyLogger info INFO: Started SelectChannelConnector@0.0.0.0:8888 Sep 01, 2015 9:17:07 PM com.google.appengine.tools.development.AbstractModule startup INFO: Module instance default is running at http://localhost:8888/ Sep 01, 2015 9:17:07 PM com.google.appengine.tools.development.AbstractModule startup INFO: The admin console is running at http://localhost:8888/_ah/admin Sep 01, 2015 9:17:07 PM com.google.appengine.tools.development.DevAppServerImpl doStart INFO: Dev App Server is now running
Once the application is running the focus will shift to the ‘Development Mode’ window where a URL will be displayed – http://127.0.0.1:8888/GWTDradAndDrop.html?gwt.codesvr=127.0.0.1:9997. Copy this URL and paste it in the Internet Explorer or your favorite browser. Remove the part after ‘.html’ and click Enter. You will get the screen as below.
You can drag the Child and drop them into different Parent.
6. Download the source file
This was an example of GWT Drag and Drop
.
You can download the full source code of this example here: GWT Drad And Drop. Please note that to save the space the lib folder is not included in the zip.