qtqtscript

QtScript: how to reload current script?


QScriptEngine has evaluate() method that can be used to load script, execute it and to run a specified function from already loaded script. But how to clear current script and load a new one? For example, i use evaluate() to load a script from file and then evaluate() to get a script functions and call them. But what can i do to clear current script and load a new one from a different file? Deleting and creating QScriptEngine seems like a solution, but it likes to be created in GUI thread (due to QScriptEngineDebugger) while all script operations are performed in separate thread. So is it any way to clear current script without re-creating QScriptEngine object?


Solution

  • I ran into this problem, and would like to improve Eye of Hell's answer (thanks, by the way!), as it leaves out an important detail.

    I'll use a cut down version of my problem, where I am reusing a QScriptEngine object and wanted to ensure that nothing was left behind between evaluations. In particular, I wanted to ensure that the onEquipped function was not called for the "RC Helicopter Controller" entity, as it doesn't change its sprite when it is equipped and hence doesn't define an onEquipped function in its script file. Simply using pushContext() and popContext() results in nothing being called at all:

    #include <QtCore>
    #include <QtScript>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);
    
        QScriptEngine scriptEngine;
    
        scriptEngine.pushContext();
        scriptEngine.evaluate("function onEquipped(entity) { print('changing pixmap to equipped sprite for ' + entity); }").toString();
        QScriptValueList args;
        args << QScriptValue("Pistol");
        scriptEngine.globalObject().property("onEquipped").call(QScriptValue(), args);
        scriptEngine.popContext();
    
        scriptEngine.pushContext();
        args.clear();
        args << QScriptValue("RC Helicopter Controller");
        scriptEngine.globalObject().property("onEquipped").call(QScriptValue(), args);
        scriptEngine.popContext();
    
        return 0;
    }
    

    The function call seems to happen on the original context, not the current one. Upon looking at QScriptEngine::pushContext() documentation, I saw that you need to explicitly use the context returned from it, and on top of that, you must use QScriptEngine::activationContext() to access any variables:

    #include <QtCore>
    #include <QtScript>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);
    
        QScriptEngine scriptEngine;
    
        scriptEngine.pushContext();
        scriptEngine.evaluate("function onEquipped(entity) { print('changing pixmap to equipped sprite for ' + entity); }").toString();
        QScriptValueList args;
        args << QScriptValue("Pistol");
        scriptEngine.currentContext()->activationObject().property("onEquipped").call(QScriptValue(), args);
        scriptEngine.popContext();
    
        scriptEngine.pushContext();
        args.clear();
        args << QScriptValue("RC Helicopter Controller");
        scriptEngine.currentContext()->activationObject().property("onEquipped").call(QScriptValue(), args);
        scriptEngine.popContext();
    
        return 0;
    }
    

    changing pixmap to equipped sprite for Pistol