B4J Question Making Upcalls from JavaScript to JavaFX?

Discussion in 'B4J Questions' started by zyblux, Mar 13, 2015.

  1. zyblux

    zyblux Member Licensed User

    Hi Everyone,
    I have recently been doing web development using B4j and found it extremely nice to use. I have no problems handling JS code from the server side and invoking JS from a desktop app using the WebView control (and JavaObject etc). But is it possible to invoke B4j code from JS running in the webview control? I found an example in the Oracle blog but not sure how to get it to work in B4j:

    Any ideas?

    Thanks

    https://blogs.oracle.com/javafx/entry/communicating_between_javascript_and_javafx

    Making Upcalls from JavaScript to JavaFX

    Since we are talking about a two-way communication channel, what about making calls in the opposite direction: from a Web application into JavaFX? On the JavaFX side, you need to create an interface object (of any class) and make it known to JavaScript by calling JSObject.setMember(). Having performed this, you can call public methods from JavaScript and access public fields of that object.


    The code below shows how to set up an interface object:


    class Bridge {
    public void exit() {
    Platform.exit();
    }
    }
    ...
    JSObject jsobj = (JSObject) webEngine.executeScript("window");
    jsobj.setMember("java", new Bridge());

    First we need a JSObject to attach our interface object to. The above code uses the JavaScript window object but any other object would work as well. Note that a cast is necessary. Then we create an interface object and add it as a new member of that JSObject. It becomes known to JavaScript under the name window.java, or just java, and its only method can be called from JavaScript as java.exit(). The upcall into Java is synchronous and occurs on the JavaFX Application thread. The following HTML code enables exiting the JavaFX application by clicking on a link:


    <p>Click
    <a href="" onclick="java.exit();">here</a>
    to exit the application

    Once you no longer need an interface object, you may want to call the JSObject.removeMember() method to make JavaScript "forget" it.
     
  2. Erel

    Erel Administrator Staff Member Licensed User

    Which type of server are you implementing? WebSockets?
     
  3. zyblux

    zyblux Member Licensed User

    Hi Erel,
    Yep, standard web sockets but I'm using the a webview control in a desktop app but I can try anything :)

    BRGDS/Chris
     
  4. Erel

    Erel Administrator Staff Member Licensed User

  5. zyblux

    zyblux Member Licensed User

    Sorry Erel, I don't think I explained myself very well. I'm trying to do a desktop/web client hybrid kind of thing.

    I have a standard desktop app with a webview control on the form. I have no problem with websockets and jQuery etc from the server side - that whole mechanism is awesome. BUT what I'm trying to do is for certain web links to trigger code on the client side "outside" of the webview control. So clicking on a <button> tag in a web page will trigger an event in the deskop UI code not the ws/server, breaking out of the whole websocket stuff. I found examples of triggering JS in the webview control from UI code but I'd like to get it working both directions.

    Cheers/Chris
     
  6. Erel

    Erel Administrator Staff Member Licensed User

  7. scrat

    scrat Active Member Licensed User

    Hi

    I have a similar problem.
    I try to use leaflet.js with b4j and i must call sub from JS to B4j and from B4j to JS.

    With B4a I use webviewextras and all works fine.

    With b4j call JS function are ok but the problem is to call B4j function from JS.

    I use this code.
    B4J
    Code:
    Dim win As JavaObject
    win=WVO.RunMethodJO(
    "getEngine",Null).RunMethodJO("executeScript"Array As String("window"))
    win.RunMethodJO(
    "setMember",Array As Object("b4j",MainForm))

    sub test
    log("from js")
    end sub
    JS
    Code:
    function userdragend() {
         b4j.test();
       
    }
    Java code from Oracle

    Code:
    public class JavaApplication {
    public void exit() {
    Platform.exit();
    }
    }
    ...
    JSObject window = (JSObject) webEngine.executeScript("window");
    window.setMember("app", new JavaApplication());
    No error but test sub is never called.
    How to pass B4J class to the webengine ?

    Thank you
     
  8. Daestrum

    Daestrum Well-Known Member Licensed User

    This example should get you started.
    Code:
    Sub Process_Globals
      
    Private fx As JFX
      
    Private MainForm As Form
      
    Dim wv As WebView
    End Sub

    Sub AppStart (Form1 As Form, Args() As String)
      wv.Initialize(
    "")
      MainForm = Form1
      MainForm.SetFormStyle(
    "UNIFIED")
      
    'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
      MainForm.Show
      
    Dim we As JavaObject
      we = asJO(wv).RunMethod(
    "getEngine",Null)
      MainForm.RootPane.AddNode(wv,
    10,10,-1,-1)
      asJO(Me).RunMethod(
    "setBridge",Array("b4j",we))
      we.RunMethod(
    "loadContent",Array($"<p>Click
    <a href="" onclick="b4j.test();">here</a>
    to exit the application"$
    ))
    End Sub

    Sub asJO(o As JavaObjectAs JavaObject
      
    Return o
    End Sub

    Sub test()
      
    Log("test")
    End Sub

    #if java

    import netscape.javascript.JSObject;
    import javafx.scene.web.WebEngine;
    import java.lang.RuntimeException;

    public static class Bridge{
       public void test() {
           try{
                 b4j.example.main._test();// redirect to b4j sub
                } catch (Exception e){
                }
        }
    }

    public static void setBridge(String s,WebEngine we){
       JSObject jsobj = (JSObject) we.executeScript("window");
       jsobj.setMember(s, new Bridge());
    }
    #end if
     
    amykonio likes this.
  9. Daestrum

    Daestrum Well-Known Member Licensed User

    A better example attached.
    This allows for calling the b4j sub by name instead of hard coding it.
    The link routine takes just the name of the sub no params
    The link2 routine takes the name plus a single parameter.
    The routines in b4j are run on a thread (runlater...)


    Note: link2 routine has some odd code as the javascript supplied an Integer and b4j wanted an int.
     

    Attached Files:

  10. scrat

    scrat Active Member Licensed User

    Thank you Daestrum, I 'll test this solution
     
  11. Eme Fibonacci

    Eme Fibonacci Well-Known Member Licensed User

    I am using the example above.
    Java inline:
    PHP:
      public void CallSub2(String sub,Object arg) { // for call with  1 param
            boolean isInt = false;
            int ti = 0;
            try{
                Class<?= Class.forName("b4j.example.main");
                Class<
    ?> ac = arg.getClass();
                if (arg instanceof java.lang.Integer){
                    ac = int.class;
                }
                final Method m = c.getDeclaredMethod("_" + sub.toLowerCase(),ac);
                final Object dummy = null;
                final Object xarg = arg;
                Platform.runLater(new Runnable(){
                    public void run(){
                        try{
                            m.invoke(dummy,xarg);
                        }catch (IllegalAccessException e){
                            System.out.println(e);
                        }catch (InvocationTargetException ite){
                        }
                    }
                });
            } catch (Exception e){
                System.out.println(e);
            }
        }
    In my javasctipt :
    Code:
    <script>
    function myFunction() {
    b4j.CallSub2(
    'Subname','Hello b4j');
    }
    </script>
    Problem:
    In B4J this works
    Code:
    Sub Subname(s As String)
        
    Log(s)
    End Sub
    But This Don't work. Why?
    Code:
    Sub Subname(s As Object)
        
    Log(s)
    End Sub
     
  12. DonManfred

    DonManfred Expert Licensed User

    1. you should have started a new thread for your issue.
    2. A javascript can not send Objects like in java. the parameter from your javascript is a string.
     
    techknight likes this.
  13. Daestrum

    Daestrum Well-Known Member Licensed User

    Change
    Code:
    Class<?> ac = arg.getClass();
    to
    Code:
    Class<?> ac = Object.class;
    Then it will call the sub with an Object parameter is Sub fred(o As Object)
     
    DonManfred likes this.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice