Replace QWebKit Object.signal.connect()



  • In QWebKit, we could bind a signal of a C++ object to a JS method with this method:

    function connectSlots() {
            if ( !connected ) {
                connected = true;
                MainWindow.signal_sensorFound.connect(this, foundSensor);
            }
    }
    

    This no longer exist in QWebEngine, this code would automatically convert the method argument of foundSensor to JS type arguments.
    I am trying to find an alternative with QWebEngine. I haven't found this specified in the documentation of Qt to migrate to QWebEngine.

    If I tried to use runJavascript and call my JS method directly, the Qt type arguments are not converted like before
    Example:

    emit signal_sensorFound(deviceType, this->lstDevicePaired.size(), this->lstDevicePaired, this->lstTypeDevicePaired, fromStudioPage); //old method with QWebKit, connect the signal to a JS method with the same number of arguments, arguments get converted automatically
    ui->webView_settings->page()->runJavaScript("alertMe();");  //this works, JS method called with success, no arguments
    ui->webView_settings->page()->runJavaScript("foundSensor(deviceType, lstDevicePaired.size(), lstDevicePaired, lstTypeDevicePaired, fromStudioPage);");  //this does not work..
    

  • Lifetime Qt Champion

    Hi,

    Not a direct answer but you might be interested by @Konstantin-Tokarev QtWebKit reboot.


  • Moderators

    The problem with this

    ui->webView_settings->page()->runJavaScript("foundSensor(deviceType, lstDevicePaired.size(), lstDevicePaired, lstTypeDevicePaired, fromStudioPage);");
    

    is that you're just evaluating a string. deviceType and the rest are just symbols that javascript doesn't know. It's like you'd write the same in the page itself without declaring these variables.
    since you're just evaluating a string you need to resolve the values of these c++ variables yourself. For example if you have a js function

    function foo(an_int, a_string) { ... }
    

    you can pass an int and a string from c++ like this:

    int bar = 42;
    QString bazz("hello");
    QString script("foo(%1,'%2');");
    page->runJavaScript(script.arg(QString::number(bar), bazz));
    


  • Thanks both for your answers!

    2 good solutions, I am not moved to QWebEngine yet, but I will probably do it.
    Everything seems to work in QWebEngine now with a few code modification.

    Merci!



  • QString script("foundSensor(%1, %2, %3, %4, %5);");
    ui->webView_settings->page()->runJavaScript(script.arg(deviceType, lstDevicePaired.size(), lstDevicePaired, lstTypeDevicePaired, fromStudioPage));
    

    trying to transfer (int, int, lst<int>, lst<int>, boolean)
    const': cannot convert argument 3 from 'QList<int>' to 'char'


  • Moderators

    You misunderstood. It's not enough to pass the variables through arg(). It's not a magic function that translates types to javascript compatible strings. You need to build these strings yourself.

    I don't know what types you use but lets say for the sake of example that they are something like this:

    int deviceType = 42;
    QList<int> lstDevicePaired = { 42, 43, 44 };
    

    To make this work in javascript you need to construct a string like this:

    "foundSensor(42, [42,43,44]);"
    

    So you can do it like this for example:

    QStringList temp;
    std::transform(lstDevicePaired.begin(), lstDevicePaired.end(), std::back_inserter(temp), [](int i){ return QString::number(i); });
    
    QString script("foundSensor(%1, [%2]);");
    QString arg1= QString::number(deviceType);
    QString arg2 = temp.join(',');
    
    ui->webView_settings->page()->runJavaScript(script.arg(arg1, arg2));
    

    Same goes of course for the other parameters. I just used first two to give you example.



  • @SGaist said in Replace QWebKit Object.signal.connect():

    Hi,

    Not a direct answer but you might be interested by @Konstantin-Tokarev QtWebKit reboot.

    Hey SGaist,

    Any idea if QWebKit will be part of a future Qt release, like 6.0? I may just wait for that instead :) Could help on the project also.
    Cheers,
    Max


  • Lifetime Qt Champion

    Do you mean the reboot ? No, I don't.

    Waiting for Qt 6 might not be the best choice, it won't get started before at least two years.



  • @maximus We have ready to use binary packages compatible with Qt 5.7, and we are planning to publish future binary builds as Qt SDK components. Plan is to make proper release from current development branch alongside with Qt 5.8

    If you are willing to help us, it would be very much welcome!



  • @Chris-Kawa said in Replace QWebKit Object.signal.connect():

    You misunderstood. It's not enough to pass the variables through arg(). It's not a magic function that translates types to javascript compatible strings. You need to build these strings yourself.

    Sorry for the old bump, just got back working on this.
    Thanks Chris for the example, I think I am constructing the JS argument fine now, the problem is that the JS function is not recognized.
    I went back to a simple example to show the problem.

    Here is the code I'm using. Now I don't have any problem from my JS to call a Qt function, the problem I'm having is calling a JS function from Qt code.

    QString jsToRun2 = "sayHello()";
    ui->webView_settings->page()->runJavaScript(jsToRun2);
    

    JS code in the html page that I control:

    function sayHello() {alert('hello');}
    

    Getting this error in the Qt console : js: Uncaught ReferenceError: sayHello is not defined


  • Moderators

    Is the page already loaded when you call this? Try this:

    connect(ui->webView_settings->page(), &QWebEnginePage::loadFinished, [&]{
        QString jsToRun2 = "sayHello()";
        ui->webView_settings->page()->runJavaScript(jsToRun2);
    });
    


  • Hey Chris,

    Yes the page was loaded. even then it seems it could not find the function. I can modify elements with jquery but not call the function.

    I changed the location of the function and it worked for some reason. I guess you can't access function when they are in document.ready part of the js

    $(function() { //loaded on dom ready, not accessible by Qt runJavascript
        function sayhello() {
           alert('say hello');
        }
    }
    

    Changed to :

        function sayhello() {
          alert('say hello'); //working here!
        }
        $(function() { /
         //other method not being call by Qt
        }
    

    Thanks for helping me figure it out.
    Fixed by moving all the function outside of the document.ready ( $(function() { )


  • Moderators

    I'm no javascript expert, but the function in your first example seems to be a local function (local to the scope of the callback), so yeah, you can't access it from a global scope. When you moved it out to the global scope it's accessible.



  • Exactly that, Thanks Chris !


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.