How do I wrap a callback using JavaScript Overlay types (GWT)?
Asked Answered
W

1

6

In the Display Object class, I have everything wrapped excepted the events. I can't not figure out the pattern and really need an example.

In JavaScript, you create a callback for the object like this:

displayObject.onPress = function(event) {
    $wnd.alert("object pressed");
}

I have wrapped the Mouse Event parameter:

public class MouseEventImpl extends JavaScriptObject {
    protected MouseEventImpl() {}

    public static native MouseEventImpl create(String type, int stageX, int stageY, DisplayObjectImpl target, JavaScriptObject nativeEvent) /*-{
        return new $wnd.MouseEvent(type, stageX, stageY, target, nativeEvent);
    }-*/;

    ...other methods excluded...
}

public class MouseEvent {
    private MouseEventImpl impl;

    public MouseEvent(String type, int stageX, int stageY, DisplayObject target, JavaScriptObject nativeEvent) {
        this.impl = MouseEventImpl.create(type, stageX, stageY, target.getOverlay(), nativeEvent);
    }

    ...other methods excluded...
}

The display object uses the same overlay pattern. How am I able to write a callback in java and pass it through to the JSO? Please provide an example if you can. :)

Washerwoman answered 7/3, 2012 at 17:56 Comment(3)
I'm not quite sure why you are using JavaScript overlays. Have you tried GwtEvent<?> and a HandlerManager for your click events? I can explain them if need be.Agincourt
EaselJS is a library for interacting with the canvas. The callback is invoked by the EaselJS engine when a particular part of the canvas is pressed. Unfortunately I can't use a GwtEvent because the DisplayObject is not a page element.Washerwoman
I see, I'll have to check that out myselfAgincourt
H
7

Pre-post edit: I wrote up this answer without actually trying to see why you were trying to do this thing, under the assumption that you were using some non-browser event, which is already wrapped up pretty nicely, and if you want more data from the NativeEvent instance, you can write JSNI methods in your own classes to get access to it, or further subclass NativeEvent to add more methods and .cast() to your class. Add the handler to a widget using the Widget.addDomHandler method and the appropriate MouseEvent subclass to get the type instance.


In JavaScript, callbacks are just functions that will be invoked when something happens. Unless specifically specified where they are passed in, they will generally be called on the global context, not on a specific object instance.

var callback = function() { alert("callback called!"); };

// later, in something that consumes that callback:
callback();

To invoke a function on an instance (i.e. make it a method invocation), one can wrap that invocation in a function that doesn't need an instance:

var obj = {};
obj.name = "Me";
obj.whenSomethingHappens = function() {
    alert("my name is " + this.name);
};

// wont work, so commented out:
//var callback = obj.whenSomethingHappens;

// instead we wrap in a function
// this is making a closure (by closing over obj)
var callback = function() {
    obj.whenSomethingHappens();
};

// later, in something that consumes that callback:
callback();

In Java, one cannot refer specifically to a method (without reflection), but only to object instances. The easiest way to build a simple callback is to implement an interface, and the code that takes the callback takes an instance of the interface, and invokes the defined method.

GWT declares a Command interface for zero-arg functions, and a generic Callback<T,F> interface for cases that may pass or fail, with one generic arg for each option. Most event handlers in GWT just define one method, with specific data passed into that method.

We need to use all of this knowledge to pass Java instances, with a function to call, into JavaScript, and make sure they are invoked on the right instance. This example is a function that takes a Callback instance and using JSNI wraps a call to it JS.

// a callback that has a string for either success or failure
public native void addCallback(Callback<String, String> callback) /*-{
    var callbackFunc = function() {
        // obviously the params could come from the function params
        [email protected]::onSuccess(Ljava/lang/String;)("success!");
    };
    doSomethingWith(callbackFunc);//something that takes (and presumably calls) the callback
}-*/;

One last piece - to let GWT's error handling and scheduling work correctly, it is important to wrap the call back to java in $entry - that last line should really be

    doSomething($entry(callbackFunc));
Hegemony answered 8/3, 2012 at 4:54 Comment(3)
Thank you for this very informative response. I'm pleased to inform I have successfully attached the click events! Much appreciationWasherwoman
eclipse complains about onSuccess(Ljava/lang/String;)("success!"); but I think could be used onSuccess(Ljava/lang/Object;)("success!"); insteadGilreath
Thanks @LorenzoSciuto, you are correct, I should have ignored the generics and gone for Object. Another option is to use *, meaning "there is only one method with this name, so you don't actually need the parameter types to figure it out".Hegemony

© 2022 - 2024 — McMap. All rights reserved.