B4J Question b4j.CallSub problem

jkhazraji

Active Member
Licensed User
Longtime User
Hello everybody.
Anybody knows why the following code is not working? Does it have anything to do with the b4j version?
I have version 10.00 Beta which is the latest as I think.
Thanks.
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private WebView1 As WebView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    Dim html As String=$"<html>
             <head>
               <script>
               var count = 0;
               function doCallback() {
                 count++ ;
                 var msg ='Hello world '+count;
                 b4j.CallSub('show_msg', msg);
                 document.getElementById('test').innerHTML='test '+count;
                 console.log(count);
               }
               </script>
             </head>
             <body>
               <div>
                 <button onclick='doCallback();'>Call Java</button>
               </div>
               <div id='test'></div>
             </body>
           </html>
    "$
    WebView1.LoadHtml(html)
    Wait For WebView1_PageFinished
    Dim we As JavaObject
    Dim jo As JavaObject=WebView1
    we = jo.RunMethod("getEngine",Null)
    (Me).As(JavaObject).RunMethod("setBridge",Array(we))
    LogError("Bridge set")
    
    

End Sub
Public Sub show_msg(msg As String)
    Log(msg)
End Sub
Private Sub WebView1_PageFinished (Url As String)
     Log("Finished page loading")
End Sub
Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub

#If java


import javafx.scene.web.WebEngine;
import netscape.javascript.JSObject;
import java.lang.RuntimeException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
import javafx.application.Platform;

import java.lang.Enum;
import java.lang.reflect.Method;
public static class Bridge{
   
    public static void CallSub(String sub,Object arg) { 
        System.out.println("CallSub called");
        boolean isInt = false;
        int ti = 0;
        try{
            Class<?> c = 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){
                    System.out.println(ite);
                    }
                }
            });
        } catch (Exception e){
            System.out.println(e);
        }
    }

}
public static void setBridge(WebEngine we){
    JSObject jsobj = (JSObject) we.executeScript("window");
    Bridge b = new Bridge();
    jsobj.setMember("b4j", b);
    System.out.println("Bridge set: " + b + " member: 'b4j'");
}
#End If
it works onky if I comment the following line which makes the code useless:
B4X:
 b4j.CallSub('show_msg', msg);
 

agraham

Expert
Licensed User
Longtime User
the following code is not working
Your description is useless. In what way is your app "not working"? There should be an error message and stack trace in the logs.

I'm not an expert in HTML but it looks like you are trying to call Java code from JavaScript code which I don't think is possible.
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
b4j.CallSub('show_msg', msg)

If this is the real callsub, the sub name is a String, so double quotes must be used...
Single quotes render the following code to be considered as comments

But again, as pointed by @agraham , you are creating a jscript and trying to call a sub from inside your jscript... never saw that before
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Where did you find the example code?

I've never tried it from a code module (Main), but it works in a class, and without having to use reflection for the subs callback.
 

Attachments

  • Test6.zip
    3 KB · Views: 130
Last edited:
Upvote 0

jkhazraji

Active Member
Licensed User
Longtime User
In JavaScript, single (' ') and double (“ ”) quotes are frequently used for creating a string literal. It is not a comment.
 
Upvote 0

jkhazraji

Active Member
Licensed User
Longtime User
Where did you find the example code?

I've never tried it from a code module (Main), but it works in a class, and without having to use reflection for the subs callback.
 
Upvote 0

jkhazraji

Active Member
Licensed User
Longtime User
And your answer is very disappointing.. there are several examples in the forum of calling Java code from Javascript. One of which is:
 
Upvote 0

FrostCodes

Active Member
Licensed User
Longtime User
Here is a sample from my project. You don't need to set a package name:


Main code:
    Dim WebviewJo As JavaObject = WebView1.As(JavaObject)
    Dim WebEngine As JavaObject = WebviewJo.RunMethodJO("getEngine",Null)
    
    Dim currentInstance As JavaObject = Me
    currentInstance.RunMethod("setBridge", Array(WebEngine))



Java part:
#if java
import netscape.javascript.JSObject;
import javafx.scene.web.WebEngine;
import anywheresoftware.b4a.BA.RaisesSynchronousEvents;

//Needs to be a global variable otherwise it appears to be garbage collected.
Bridge b;

public class Bridge{
    public Object callSub(String sub) { // for call with no parameters
        return ba.raiseEvent2(this, false,sub.toLowerCase(),true);
    }
    public Object callSub2(String sub, String arg1) { // for call with  1 param
        return ba.raiseEvent2(this, false, sub.toLowerCase() , true, arg1);
    }
    public Object callSub3(String sub, String arg1, String arg2) { // for call with  2 params
        return ba.raiseEvent2(this, false, sub.toLowerCase(), true, arg1, arg2);
    }
}
public void setBridge(WebEngine we) {
    
    JSObject jsobj = (JSObject) we.executeScript("window");
    b = new Bridge();
    jsobj.setMember("b4j", b);
    
    }
#end if


Now in the js part, you can call b4j.callSub() or b4j.callSub2() or b4j.callSub3()
 
Upvote 0

jkhazraji

Active Member
Licensed User
Longtime User
Where did you find the example code?

I've never tried it from a code module (Main), but it works in a class, and without having to use reflection for the subs callback.
That was really concise, precise, and up to the point as my teacher in the medical school used to say.
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…