What is the equivalent of JavaScript's setTimeout on qtScript?

后端 未结 5 1262
清酒与你
清酒与你 2021-01-04 11:18

Not much to add; what is the equivalent of JavaScript\'s setTimeout on qtScript?

相关标签:
5条回答
  • 2021-01-04 11:29

    You can expose the QTimer as an instantiable class to the script engine. You can then instantiate it via new QTimer().

    This is documented in Making Applications Scriptable.

    Below is a complete example. The timer fires a second after the script is evaluated, prints timeout on the console, and exits the application.

    // https://github.com/KubaO/stackoverflown/tree/master/questions/script-timer-11236970
    #include <QtScript>
    
    template <typename T> void addType(QScriptEngine * engine) {
       auto constructor = engine->newFunction([](QScriptContext*, QScriptEngine* engine){
          return engine->newQObject(new T());
       });
       auto value = engine->newQMetaObject(&T::staticMetaObject, constructor);
       engine->globalObject().setProperty(T::staticMetaObject.className(), value);
    }
    
    int main(int argc, char ** argv) {
       QCoreApplication app{argc, argv};
    
       QScriptEngine engine;
       addType<QTimer>(&engine);
       engine.globalObject().setProperty("qApp", engine.newQObject(&app));
    
       auto script =
             "var timer = new QTimer(); \n"
             "timer.interval = 1000; \n"
             "timer.singleShot = true; \n"
             "var conn = timer.timeout.connect(function(){ \n"
             "  print(\"timeout\"); \n"
             "  qApp.quit(); \n"
             "}); \n"
             "timer.start();\n";
    
       engine.evaluate(script);
       return app.exec();
    }
    
    0 讨论(0)
  • 2021-01-04 11:29

    Qt provides an example in the 'context2d' project a way to access to the setInterval/clearInterval setTimeout/clearTimeout functionalities from the script.

    In the 'Environment' class of this project, the startTimer function of a QObject is called each time that the script invokes setInterval/setTimeout. Then the timer identifier is added in a QHash with a reference on the javascript callback. When the countdown of the timer (c++ part) is over, the timerEvent of the 'Environment' class is called and then the javascript callback called..

    Note that all the timers are killed in the Environment::reset() in order to clean the context.

    see: https://doc.qt.io/archives/qt-4.7/script-context2d.html

    0 讨论(0)
  • 2021-01-04 11:47

    Here's my submission for "kludge of the year"... but this works AND doesn't require recompiling the C++ back end, in a context where that is way too much work to get involved with! I'm not sure how the rest of you may be using the now defunk Qt Script, but my need is for the Qt Installer Framework, and I want to just use it out of the box - not via a custom fork of the whole tool set, for me to then try to maintain (since QtIFW itself is still actively updated), or have to port around, compile on alternate platforms, share with collaborators...

    So what's my solution? Well there's no QTimer exposed the to standard script engine, but you can define your own custom (i.e. "dynamic") installer wizard pages, defining the interface via Qt forms (.ui files). With that, you can drop in any QWidget, and then add connections for the signals and slots on the Qt Script side... And so, I just used the first, and perhaps most simplistic, set of widget signals and slots which I saw had some sort of timer mechanism built in that I might capitalize upon.

    In a custom form, drop this in somewhere, adding a hidden QPushButton:

    <widget class="QPushButton" name="timerKludgeButton">
     <property name="visible">
      <bool>false</bool>
     </property>     
    </widget>
    

    Then, when you load the component containing the .ui (form), connect the button's "released" signal to a custom "slot" (i.e. Qt Script function):

    Component.prototype.componentLoaded = function(){   
        var page = gui.pageWidgetByObjectName("DynamicMyTimerKludgePage");
        page.timerKludgeButton.released.connect(this, this.onTimeOut);
    }
    

    Next, define the slot:

    Component.prototype.onTimeOut = function(){
        console.log("Asynchronous time out!");
    }
    

    Finally, where applicable, start your "timer" with the core trick here, using the QPushButton's "animateClick" function:

    var page = gui.pageWidgetByObjectName("DynamicMyTimerKludgePage");
    page.timerKludgeButton.animateClick(2000);
    
    0 讨论(0)
  • 2021-01-04 11:48

    Here's how you can extend your script language, by providing a self-contained C++ method (no need for bookkeeping of timer ids or so). Just create the following slot called "setTimeout":

    void ScriptGlobalObject::setTimeout(QScriptValue fn, int milliseconds)
    {
      if (fn.isFunction())
      {
        QTimer *timer = new QTimer(0);
        qScriptConnect(timer, SIGNAL(timeout()), QScriptValue(), fn);
        connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));
        timer->setSingleShot(true);
        timer->start(milliseconds);
      } else
        context()->throwError(tr("Passed parameter '%1' is not a function.").arg(fn.toString()));
    }
    

    And introduce that slot as function to the global object of your script engine. This can be done in different ways, e.g. just creating a QScriptValue-function via the QScriptEngine instance, and setting an accordingly named property on the engine's existing global object. In my case however, the entire ScriptGlobalObject instance is set as new global object, like this:

    mScriptGlobalObject = new ScriptGlobalObject(this);
    engine->setGlobalObject(engine->newQObject(mScriptGlobalObject));
    

    Note that if you want to use "context()" as shown in the setTimeout code above, your ScriptGlobalObject should derive also from QScriptable, like this:

    class ScriptGlobalObject : public QObject, protected QScriptable
    

    In the script you can now use setTimeout to have a method invoked at a later time (as long as the QScriptEngine instance from which it originates isn't deleted in the meantime):

    setTimeout(function() {
      // do something in three seconds
    }, 3000);
    
    0 讨论(0)
  • 2021-01-04 11:48

    setTimeout and setInterval are not defined in ECMAScript specification because they are not JavaScript features. These functions are part of browser environments. So, QTscript does not have them.

    You can use QTimer to achive this functionality. Here is a quick code how to use it in QTScript.

    var timer = new QTimer();
    timer.interval = 100; // set the time in milliseconds
    timer.singleShot = true; // in-case if setTimout and false in-case of setInterval 
    timer.timeout.connect(this, function(){console("in setTimout")});
    timer.start();
    

    Watch out for any bugs, I just coded it here.

    0 讨论(0)
提交回复
热议问题