2008-11-17 15 views
10

Je développe une applet Java invisible, qui sera entièrement contrôlée à partir de JavaScript.Comment enregistrer un rappel JavaScript dans une applet Java?

Je peux appeler les méthodes Java de l'applet facilement, et je peux appeler des méthodes JavaScript depuis l'applet en utilisant netscape.javascript.JSObject.getWindow(this).call().

Mais pour enregistrer un rappel JavaScript dans l'applet, j'imagine que j'aurais besoin d'un objet fonction JavaScript quelconque.

Je voudrais faire:

public void registerCallback(SomeJavascriptFunction func) { ... } 

Ce que je pourrais appeler de Javascript:

myapplet.registerCallback(function(){ alert("called back"); }); 

donc je pourrais appeler cette fonction dans le code plus tard:

func.call(...); 

Est-ce que quelque chose comme ça existe? Comment puis-je faire ceci? Rigide maintenant Je pense à créer un peu de Javascript pour gérer ce mécanisme de rappel au lieu de le faire depuis l'applet.

Répondre

2

Je suis tout nouveau à Java < -> communication JavaScript, comme je l'ai prévu de l'explorer cette semaine. Une bonne opportunité ici ... :-)

Après quelques tests, il semble que vous ne pouvez pas passer une fonction JS à une applet Java. À moins que je fais de la mauvaise façon ...

J'ai essayé:

function CallJava() 
{ 
    document.Applet.Call("Does it work?"); 
    document.Applet.Call(function() { alert("It works!"); }); 
    document.Applet.Call(DoSomething); // A simple parameterless JS function 
    document.Applet.Call(window.location); 
} 
function DumbTest(message, value) 
{ 
    alert("This is a dumb test with a message:\n" + message + "\n" + value); 
} 

où appel est (sont) défini comme:

public void Call(String message) 
{ 
    JSObject win = (JSObject) JSObject.getWindow(this); 
    String[] arguments = { "Call with String", message }; 
    win.call("DumbTest", arguments); 
} 

public void Call(JSObject jso) 
{ 
    JSObject win = (JSObject) JSObject.getWindow(this); 
    String[] arguments = { "Call with JSObject", jso.toString() }; 
    win.call("DumbTest", arguments); 
} 

Quand je passe une fonction JS (tous les tests en FF3), j'obtiens une valeur nulle du côté Java. Notez que la routine Java suivante permet d'afficher le code JS de la fonction DumberTest!

public int Do() 
{ 
    JSObject win = (JSObject) JSObject.getWindow(this); 
    JSObject doc = (JSObject) win.getMember("document"); 
    JSObject fun = (JSObject) win.getMember("DumberTest"); 
    JSObject loc = (JSObject) doc.getMember("location"); 
    String href = (String) loc.getMember("href"); 
    String[] arguments = { href, fun.toString() }; 
    win.call("DumbTest", arguments); 
    return fun.toString().length(); 
} 

Au point: je fait une fonction JS:

function RegisterCallback(cbFunction) 
{ 
    var callback = cbFunction.toString(); // We get JS code 
    var callbackName = /^function (\w+)\(/.exec(callback); 
    document.Applet.RegisterCallback(callbackName[1]); 
} 

-je extraire le nom de la fonction JS du résultat toString et le transmettre à applet Java. Je ne pense pas que nous pouvons gérer les fonctions anonymes parce que Java appelle les fonctions JS par leur nom.

côté Java:

String callbackFunction; 
public void RegisterCallback(String functionName) 
{ 
    callbackFunction = functionName; 
} 
void UseCallbackFunction() 
{ 
    if (callbackFunction == null) return; 
    JSObject win = (JSObject) JSObject.getWindow(this); 
    win.call(callbackFunction, null); 
} 
+0

Il semble que vous ne pouvez passer des fonctions Java par nom, donc ce que vous devez faire est de créer un objet de façade qui enveloppait l'applet et qui prendrait des références de fonction et trouver des noms temporaires pour eux. – w00t

1

win.eval() appellera un javascript prédéfini.

String callbackFunction; 
public void RegisterCallback(String functionName) 
{ 
    callbackFunction = functionName; 
} 
void UseCallbackFunction() 
{ 
    if (callbackFunction == null) return; 
    JSObject win = (JSObject) JSObject.getWindow(this); 
    win.eval(callbackFunction); 
} 
+0

eval est plus générique, donc moins efficace qu'appeler pour cette tâche précise, et il est plus complexe de passer des paramètres à la fonction JS. – PhiLho

4

Je sais que c'est un vraiment vieille question, mais il se classait 2e dans l'une de mes recherches pour quelque chose d'autre, et je pense que le ci-dessous peut aider quelqu'un d'autre qui trouve cela.

J'ai récemment fait quelque chose de similaire, par lequel une applet Java doit rappeler en JavaScript à la fin d'une tâche, appelant différentes fonctions en cas de succès ou d'erreur. Comme cela a été le cas ces derniers temps, mes besoins consistaient à appeler des fonctions anonymes définies comme des paramètres transmis à d'autres fonctions. Ceci est le javascript sur le côté client:

applet.DoProcessing({ 
    success: function(param) { 
     alert('Success: ' + param); 
    }, 
    error: function(param) { 
     alert('Failed: ' + param); 
    } 
}); 

Comme mentionné dans les autres réponses, Java ne peut appeler les méthodes JavaScript par son nom. Cela signifie que vous avez besoin d'une méthode de rappel global, qui peut ensuite appeler à d'autres méthodes comme il le faut:

function ProcessingCallback(isSuccessful, cbParam, jsObject) { 
    if (isSuccessful && jsObject.success) 
     jsObject.success(cbParam); 
    else if (!isSuccessful && jsObject.error) 
     jsObject.error(cbParam); 
} 

Cette fonction est appelée directement à partir de l'applet Java:

public void DoProcessing(final Object callbacks) { 
    //do processing.... 


    JSObject w = JSObject.getWindow(this); 
    //Call our named callback, note how we pass the callbacks parameter straight 
    //back out again - it will be unchanged in javascript. 
    w.call("ProcessingCallback", new Object[]{successful, output, callbacks}); 
} 

Vous pouvez tenir la référence de l'objet paramètre étant transmise indéfiniment si vous souhaitez l'utiliser comme une forme de rappel enregistré plutôt que comme un rappel si nécessaire, etc.

Dans notre cas, le traitement peut être intensif en temps, donc nous tournons réellement un autre fil - le cal lbacks travaillent encore ici aussi:

public void DoProcessing(final Object callbacks) { 
    //hold a reference for use in the thread 
    final Applet app = this; 

    //Create a new Thread object to run our request asynchronously 
    //so we can return back to single threaded javascript immediately 
    Thread async = new Thread() { 
     //Thread objects need a run method 
     public void run() { 
      //do processing.... 


      JSObject w = JSObject.getWindow(app); 
      //Call our named callback, note how we pass the callbacks parameter 
      //straight back out again - it will be unchanged in javascript. 
      w.call("ProcessingCallback", new Object[]{successful, output, callbacks}); 
     } 
    } 
    //start the thread 
    async.start(); 
}