Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt C++ application connecting signals to JavaScript?



  • I am developing a Qt application that implements a GUI based on an XML file, so far so good, now I want to add Javascript to the XML file and connect signals from Qt controls to Javascript functions.

    I've seen this on QML and Javascript:
    http://doc.qt.io/archives/qt-4.8/qdeclarativejavascript.html

    Is it possible from a Qt C++ application?

    Here is the definition that creates a QPushButton:

    <button id="btn1" x="160" y="116" width="80"
            properties="QPushButton {border: 1px solid yellow;
    		          border-radius: 4px;
    		   		padding: 1px 18px 1px 3px;
    			      min-width: 6em}">						
        <state value="off" text="Off"/>
        <state value="on" text="On"/>
        <signal name="pbtnClicked">
    	<subscriber sid="win2:title"/>
    	<script>
    	    function onClick() {
                };					
    	</script>
        </signal>	
        <signal name="pbtnPressed"/>
        <signal name="pbtnReleased"/>
        <signal name="pbtnToggled"/>
    </button>
    

    What I would like to do is be able to connect the javascript function with the signal in C++...

    Can this be done?


  • Moderators

    @SPlatten said in Qt C++ application connecting signals to JavaScript?:

    What I would like to do is be able to connect the javascript function with the signal in C++

    Something like this?

    QJSEngine* engine = ...;
    connect( button, &QPushButton::clicked, this, [engine] () {
         QString script = ...
         QJSValue returnValue = engine->evaluate(script);
    }
    

    See the docs for how the script should look like



  • Thank you, I'll take a look.



  • What sort of thing can QJSEngine do and not do?

    In my simple test code I tried:

        QObject::connect(pobjPushButton
                        ,&QPushButton::clicked
                        ,[pobjScriptEng]() {
                             pobjScriptEng->evaluate("alert('hello');");
                                           });
    

    I put a break point on the line inside the callback and when I clicked on the pushbutton I could see the debugger stop on the evaluate line, but having executed the line, I didn't the alert displayed and no error was thrown.

    Can anyone help?

    I've got a little bit further by including a call:

        mspobjJSeng->installExtensions(QJSEngine::AllExtensions);
    

    I don't think 'alert()' is supported.


  • Lifetime Qt Champion



  • Thank you, info does work and has the advantage of adding a new line for each entry...

    I've just put in:

        console.info("QJSEngine");
        console.info(this);
    

    Is there anyway to debug the script or to see what members are visible in 'this' ?


  • Lifetime Qt Champion

    Hi
    As far as i know, you cant.
    However, if you see in
    https://doc.qt.io/qt-5.11/whatsnew57.html
    section Qt QML Module
    says
    "Enabled all debug services to work with QJSEngine (instead of QQmlEngine), which allows non-QML JavaScript debugging or profiling."

    so i assume if you have a js file, you can actualy debug this and see members.
    However, Not inside a mere string in a c++ file.



  • I've hit another problem now, I'm trying to pass in a QString containing a script that was read from file, however when I try to assign this:

        QObject::connect(pobjPushButton
                        ,&QPushButton::clicked
                        ,[pobjScriptEng]() {
                    pobjScriptEng->evaluate(static_cast<const QString>(strScript));
                                });
    

    I get:

       variable 'strScript' cannot be implicitly captured in a lambda with no capture-default specified
    

    What does this mean?



  • Hi @SPlatten,

    This means you need to "capture" the variable you want to use in the lambda. This tells to the compiler that have to keep the variable, usually a local one, in the memory to be accessible when the lambda is called.

    Capturing the variable is done by adding its name inside the brackets []. You can also add & suffix for passing variable by reference, in.

        QObject::connect(pobjPushButton
                        ,&QPushButton::clicked
                        ,[pobjScriptEng, &strScript]() { //or [&] to use the "by-reference capture default" mode
                    pobjScriptEng->evaluate(static_cast<const QString>(strScript));
                                });
    

    More informations here: https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture



  • Thank you, I will take a look now.



  • Is there any way to link the signal with a specific function in the script?



  • It's all in the docs http://doc.qt.io/qt-5/qjsengine.html

    QJSvalue module = myEngine.importModule("./math.mjs");
    QJSValue sumFunction = module.property("sum");
    QJSValue result = sumFunction.call(args);
    

    This will call the function sum from the module math.mjs passing args as arguments



  • Thank you, I will have a good read of the documentation....


Log in to reply