Search code examples
gwtgwt2drag-and-drop

Drag and Drop in GWT 2.4


I have a custom widget that is actually an image, and i would like to be able to drag it inside an AbsolutePanel and get its coordinates every time. I would like to use the new DND API from GWT 2.4, but i'm having a hard time to implement it. Can someone propose the basic steps i must take?


Solution

  • The new DnD API introduced with GWT 2.4 doesn't currently support the AbsolutePanel (see the implementations of the HasAllDragAndDropHandlers interface). Looking at the implementation of FocusPanel it shouldn't be too hard to enable it for other panels.

    Here's a quick proof of concept on how to solve your problem:

    public void onModuleLoad() {
        DragImage image = new DragImage();
        image.setUrl(Resources.INSTANCE.someImage().getSafeUri());
        final DropAbsolutePanel target = new DropAbsolutePanel();
        target.getElement().getStyle().setBorderWidth(1.0, Unit.PX);
        target.getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
        target.getElement().getStyle().setBorderColor("black");
        target.setSize("200px", "200px");
    
        // show drag over effect
        target.addDragOverHandler(new DragOverHandler() {
    
            @Override
            public void onDragOver(DragOverEvent event) {
                target.getElement().getStyle().setBackgroundColor("#ffa");
            }
        });
    
        // clear drag over effect
        target.addDragLeaveHandler(new DragLeaveHandler() {
    
            @Override
            public void onDragLeave(DragLeaveEvent event) {
                target.getElement().getStyle().clearBackgroundColor();
            }
        });
    
        // enable as drop target
        target.addDropHandler(new DropHandler() {
    
            @Override
            public void onDrop(DropEvent event) {
                event.preventDefault();
                // not sure if the calculation is right, didn't test it really
                int x = (event.getNativeEvent().getClientX() - target.getAbsoluteLeft()) + Window.getScrollLeft();
                int y = (event.getNativeEvent().getClientY() - target.getAbsoluteTop()) + Window.getScrollTop();
                target.getElement().getStyle().clearBackgroundColor();
                Window.alert("x: " + x + ", y:" + y);
                // add image with same URL as the dropped one to absolute panel at given coordinates
                target.add(new Image(event.getData("text")), x, y);
            }
        });
    
        RootPanel.get().add(image);
        RootPanel.get().add(target);
    }
    

    And here the custom panel

    public class DropAbsolutePanel extends AbsolutePanel implements HasDropHandlers, HasDragOverHandlers,
            HasDragLeaveHandlers {
    
        @Override
        public HandlerRegistration addDropHandler(DropHandler handler) {
            return addBitlessDomHandler(handler, DropEvent.getType());
        }
    
        @Override
        public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
            return addBitlessDomHandler(handler, DragOverEvent.getType());
        }
    
        @Override
        public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
            return addBitlessDomHandler(handler, DragLeaveEvent.getType());
        }
    }
    

    and image class:

    public class DragImage extends Image {
    
        public DragImage() {
            super();
            initDnD();
        }
    
        private void initDnD() {
            // enables dragging if browser supports html5
            getElement().setDraggable(Element.DRAGGABLE_TRUE);
            addDragStartHandler(new DragStartHandler() {
    
                @Override
                public void onDragStart(DragStartEvent event) {
                    // attach image URL to drag data
                    event.setData("text", getUrl());
                }
            });
        }
    }