2

一般目标:从javascript调用一些非静态java方法

描述:在 Java Applet 代码中的 DOM 上找到 gwt 的小部件并调用它的 java 方法(非静态)


JSObject win = JSObject.getWindow(this);
JSObject doc = (JSObject) win.getMember("document");
JSObject gwtWidget = (JSObject) doc.call("getElementsByName", widgetName);

//todo: have possibility to call `exported` java method over here, smth like:
//Object[] params = new Object[1];
//params[0] = widgetName;
//Object result = gwtWidget.call("exportedJavaMethod", params);

//todo: or just call global ($wnd) static JSNI bridge method:
//Object result = win.call("exportedJavaMethod", params);
//

问题是:我可以通过小部件的 id 找到小部件,但它是 DivElement ,它没有任何导出的实例方法。

我的小部件类是可导出的(gwt-export):


@Export(value="somewidget")
public class SomeWidget extends SimplePanel implements ..., Exportable {
    private final String id = "id_some_widget_" + count++;
    private static int count = 0;

    public SomeWidget () {
        getElement().setAttribute("name", id);
        getElement().setId(id);
    }
    ...

    public static Element getInstanceById(String elementId) {
        Element someWidget= DOM.getElementById(elementId);
        return someWidget;
    }

    public String getSomeInstancedData() {
        return "useful_inner_data" + this.id;
    }

因此,例如,我想找到添加到 DOM 的具体小部件并getSomeInstancedData()在 javascript 中调用非静态方法。有可能吗?

假设像:


var someWidget = document.getElementById(widgetId);
alert(someWidget.getSomeInstancedData());

//or:
var someWidgetExported = com.mypackage.widgets.somewidget.getInstanceById(listenerId);
alert(someWidgetExported.getSomeInstancedData());

在基本模块中,我写道:


ExporterUtil.exportAll();

有一个 View(ViewWithSomeWidget.ui.xml) 包含这个小部件:

...
基地:形式
base:SomeWidget ui:field="someWidget" ...
...
/base:SomeWidget
...

当 SomeWidget 没有实现 Exportable 时,项目运行良好,但我无法调用找到的小部件的 DIV 元素的非静态方法。

到那时,为了解决问题 SomeWidget 实现了 Exportable,但是由于 ClassCastException 使用延迟绑定,progect 没有很好地显示带有 SomeWidget 的 View:


ClassCastException: com.mypackage.widgets.SomeWidgetExporterImpl cannot be cast to com.mypackage.widgets.SomeWidget

那么,可能还有其他方法可以找到小部件的 javascript 对象并将其称为导出的 java 方法吗?无论如何,任何想法都非常受欢迎。

4

3 回答 3

11

您可以声明一个 javascript 函数,该函数将触发非静态方法。

例如:

package com.example;
public class Layout extends VLayout() {
    private String nonStaticVar = "nonStaticVar";
    public Layout() {
        declareMethod(this);
    }

    //Method which declares non-static method in javascript
    public native void declareMethod(Layout layout) /*-{
        var layout = layout;
        $wnd.doSomething = function(someString) {
            layout.@com.example.Layout::doSomething(Ljava/lang/String;)(someString);
        }
    }-*/;

    //Non static method which is being called
    public String doSomething(String someString) {
        //Do something, e.g. set var in this instantiated class, or output stuff
        this.nonStaticVar = someString;
        Window.alert(someString);
    }
}

现在,调用 doSomething("bla"); from javascript 将调用您的非静态方法。

于 2012-09-03T15:04:36.713 回答
4

您可以在 div 元素上定义一个自己的 jsmethod,它可以调用一个小部件方法

@Export(value="somewidget")
public class SomeWidget extends SimplePanel implements ..., Exportable {
    private final String id = "id_some_widget_" + count++;
    private static int count = 0;

    public SomeWidget () {
        getElement().setAttribute("name", id);
        getElement().setId(id);
        attachInstanceHook(getElement());
    }
    ...

    public String getSomeInstancedData() {
        return "useful_inner_data" + this.id;
    }


    private native void attachInstanceHook(Element element) /*-{
        var elem = element;
        var widget = this;
        elem.getWidgetData = function () {
            widget.@your.package.name.SomeWidget::getSomeInstancedData()();
        };

    }-*/;

您的 js 代码应如下所示:

var someWidget = document.getElementById(widgetId);  //the id of the div element
alert(someWidget.getWidgetData());
于 2012-09-21T07:29:12.997 回答
1

instead of trying to fetch the widget through its DOM element, inject its Java instance first to the global scope and refer to it:

public class SomeWidget extends SimplePanel implements ..., Exportable {

    //...

    public SomeWidget () {
        getElement().setAttribute("name", id);
        getElement().setId(id);

        attachToGlobalScope(id, this);
    }

    private native void attachToGlobalScope(String id, SomeWidget instance) /*-{
        $wnd.shared[id] = instance;
    }-*/;

    //...
}

than later, update the corresponding fetch in the Applet API layer:

JSObject win = JSObject.getWindow(this);
JSObject shared = (JSObject) win.getMember("shared");
Widget widgetRef = (Widget) shared.getMember(widgetId);

disclaimer: this somewhat crooked solution relays on JavaScript global scope variables, which is considered bad practice in general, but here acts as the only common scope, thus abused for objects storage.

于 2012-05-05T08:53:01.937 回答