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

Help with timer and JavaScript slot.



  • In my C++ engine I create an instance of QTimer that connects to a JavaScript function. The timer creation is ok and works but the slot isn't being called when the timeout signal occurs and I can see that I am getting the error:

    QObject: Cannot create children for a parent that is in a different thread.
    

    The timer is created with:

    ptmrScript = new QTimer;
    

    I'm using the QJSEngine and connecting the signal and slot:

    QMetaObject::Connection cn = QObject::connect(ptmrScript
                                                 ,&QTimer::timeout
                                                 ,[pobjScriptEng
                                                 ,crstrID
                                                 ,strScript
                                                 ,slstScript]() {
        ...
    

    I've also tried creating the timer using a pointer to QJSEngine:

    ptmrScript = new QTimer(pobjScriptEng);
    

    Same result, how can I fix this as the JavaScript slot isn't being called.



  • @SPlatten I am always surprised how complicated you are trying to solve common issues.

    What is the real issue here?
    You want to create a timer in a specific thread and start it. I am right?
    QTimer muss be started, and stopped from the owned thread.
    That's not so complicated to solve:

    auto myTimer = new  QTimer();
    connect(myTimer; &QTimer::timeout, ...);
    // move to thread
    myTimer->moveToThread(theWorkingThread);
    
    // start the timer
    QTimer::singleShot(0, myTimer, [myTimer]() { myTimer->start(); } );
    

  • Moderators

    It's a runtime error, so I can't tell if this is the correct piece of code you're showing us. So:

    If the QT_FATAL_WARNINGS environment variable is set, qWarning() exits after printing the warning message. This makes it easy to obtain a backtrace in the debugger.

    From https://doc.qt.io/qt-5/debug.html.

    Set the environment variable and extract a stack trace; paste the trace here and we can talk more.



  • @kshegunov , I will look at the link and get back to you.

    I added:

    export QT_DEBUG_PLUGINS=1
    export QT_FATAL_WARNINGS=1
    

    To ~/.profile, I also went to Project Settings -> Environment and added the same environment variables to Qt Creator.

    When I build my project now it terminates instantly, this is the application output:

    2021-12-30 07:06:58.865187+0000 XMLMPAM[5523:56476] QFactoryLoader::QFactoryLoader() checking directory path "/Users/sy/Qt/5.15.2/clang_64/plugins/platforms" ...
    2021-12-30 07:06:58.874330+0000 XMLMPAM[5523:56476] QFactoryLoader::QFactoryLoader() looking at "/Users/sy/Qt/5.15.2/clang_64/plugins/platforms/libqcocoa.dylib"
    2021-12-30 07:06:58.874511+0000 XMLMPAM[5523:56476] Found metadata in lib /Users/sy/Qt/5.15.2/clang_64/plugins/platforms/libqcocoa.dylib, metadata=
    {
        "IID": "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.3",
        "MetaData": {
            "Keys": [
                "cocoa"
            ]
        },
        "archreq": 0,
        "className": "QCocoaIntegrationPlugin",
        "debug": false,
        "version": 331520
    }
    

    This looks like a different issue...I've reverted from implementing these environment variables as this isn't the same issue and I cannot use these to get where I need to be to fault find.

    It seems the issue I'm having is using a lambda JavaScript function with the timer signal, can anyone help?



  • @SPlatten said in Help with timer and JavaScript slot.:

    It seems the issue I'm having is using a lambda JavaScript function with the timer signal, can anyone help?

    I'm afraid I do not have the solution, but have you at least verified this claim? You may well be right, but why don't you temporarily test with a regular function slot so you know whether lambda is relevant to the issue? And a lambda slot on a non-timer signal.



  • @JonB , I know the timer and connection to a slot works perfectly fine as I use this technique elsewhere.


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    export QT_DEBUG_PLUGINS=1

    I didn't say you should include this. This is when you're attempting to track errors in the plugins loading, you're not, are you?



  • @SPlatten
    Based on nothing, I'd find it "surprising" if the existence of a lambda in itself causes a thread to be spawned/involved.

    Meantime I think you should follow @kshegunov's request: test QT_FATAL_WARNINGS=1 but not with QT_DEBUG_PLUGINS=1.



  • @kshegunov , with just:

    QT_FATAL_WARNINGS
    

    set to 1, I don't get the initial problem however the result is no different and in my debug output I still get:

    S000000000029E000000002424T08:09:54.416W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNativeSocketEngine(0x6000000122f0), parent's thread is clsServer(0x600000252c00), current thread is clsThread(0x600002632700)
    S000000000030E000000002424T08:09:54.416W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNativeSocketEngine(0x600000014140), parent's thread is clsServer(0x600000252140), current thread is clsThread(0x600002632700)
    S000000000031E000000002424T08:09:54.416W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNativeSocketEngine(0x60000000b0b0), parent's thread is clsServer(0x600000250b60), current thread is clsThread(0x600002632700)
    

    Where everything before : is my own tracking information.



  • @JonB I think the thread is related to the JavaScript function call in the Lambda:

    QMetaObject::Connection cn = QObject::connect(ptmrScript
                                                 ,&QTimer::timeout
                                                 ,[pobjScriptEng
                                                 ,ptmrScript
                                                 ,strFile
                                                 ,strFunc
                                                 ,strScriptWithCall]() {
       QJSValue objResult(pobjScriptEng->evaluate(strScriptWithCall));
       QString strError;
       if ( objResult.isError() == true ) {
           strError = QString("%1\n%2\n%3").arg(strFile).arg(strFunc)
                                           .arg(objResult.toString());
       } else {
           QString strResult(objResult.toString());
           if ( strResult.compare("undefined") != 0 ) {
               strError = strResult;
           }
        }
        if ( strError.isEmpty() != true ) {
            clsXMLnode* pobjRoot(clsXMLnode::spobjGetRoot());
            emit pobjRoot->error(strError);
            ptmrScript->deleteLater();
        }
    });
    


  • @SPlatten
    I just don't see where/why a lambda will behave differently from a C++ method here, as you say it does. Maybe your issue lies in the calls of the body of the lambda, which is a different matter, and ought show up equally in a method instead.

    But ignore me because I won't have a solution. @kshegunov is much more likely to spot/offer one... :)


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    I don't get the initial problem however the result is no different and in my debug output I still get:

    It is not a fix, it's a technique to track down where the problem occurs. Also, "debug output" != "stack trace". When the debugger trips the assertion with QT_FATAL_WARNINGS on it's going to stop in all threads. Then you can go to creator's call stack view (or whatever IDE you're using) and you can extract the exact backtrace, which is what I requested. I don't expect the output the change, as nothing's been done at this point beside making the program crash, instead of silently (and wrongfully) succeeding.

    @JonB I think the thread is related to the JavaScript function call in the Lambda

    Why? How do you figure this out? I have no indication that this is where the warning's been emitted, it can be anyplace else.



  • @kshegunov , please see edit of my last post which includes the body of the lambda. The execution doesn't stop, there is just output to the debug.


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    @kshegunov , please see edit of my last post which includes the body of the lambda. The execution doesn't stop, there is just output to the debug.

    I have a fairly good idea where the problem may be, but I prefer not to speculate at this point. If the program doesn't stop and the mentioned environment variable is set, then you're not running your application in debug mode - check this and adjust accordingly.



  • @kshegunov , 100% I'm in debug, I'm running in Qt Creator debug and developing. I have a function called createTimer here is the prototype:

    Q_INVOKABLE void createTimer(const QString& crstrID
                                ,const uint cuintInterval
                                ,const QString& crstrFunction);
    

    The implementation:

    /**
     * @brief clsScriptHelper::createTimer
     * @param crstrID : Constant reference to Timer ID
     * @param cuintInterval : Constant millisecond interval
     * @param crstrFunction : Constant reference to JSfile@Function
     */
    void clsScriptHelper::createTimer(const QString& crstrID, const uint cuintInterval
                                     ,const QString& crstrFunction) {
        if ( crstrID.trimmed().isEmpty() == true || cuintInterval == 0
          || crstrFunction.trimmed().isEmpty() == true
          || crstrFunction.indexOf(clsXMLnode::msccScriptDelimiter) == -1 ) {
        //One or more of the parameters are invalid, do nothing
            return;
        }
        //Get Application instance
        clsMainWnd* pAppInstance(clsMainWnd::pobjGetAppWnd());
        if ( pAppInstance == nullptr ) {
        //Cannot get application instance!
            return;
        }
        //Look for registered timer
        QTimer* ptmrScript(pAppInstance->ptmrGetTimer(crstrID));
        if ( ptmrScript != nullptr ) {
        //Already registered, do nothing
            return;
        }
        //No timer locatd with that ID, its safe to proceed
        QStringList slstScript = crstrFunction.split(clsXMLnode::msccScriptDelimiter);
        mpScripts* pmpScriptsMap;
        if ( slstScript.length() == SSF_PARAM_COUNT
        && (pmpScriptsMap = clsMainWnd::pmpGetScriptsMap()) != nullptr ) {
        //Look for the script in the scripts map
            mpScripts::iterator itrScript(pmpScriptsMap->find(slstScript[SFF_FILE_IDX]));
            if ( itrScript != pmpScriptsMap->end() ) {
        //Found it, build the script up ready for the signal connection
                QString strScript(itrScript->second);
        //Get pointer to script engine
                QJSEngine* pobjScriptEng(clsJSON::pobjGetScriptEng());
        //Create new timer
                ptmrScript = new QTimer();
        //Register the new timer using the supplied ID
                pAppInstance->registerTimer(ptmrScript, crstrID);
        //Add any globals to the script
                clsScriptHelper::pobjGetInstance()->addGlobals(pobjScriptEng);
        //Build up script function call
                QString strFile(slstScript[SFF_FILE_IDX])
                       ,strCall(slstScript[SSF_FUNCTION_IDX])
                       ,strScriptWithCall(strScript)
                       ,strFunc(strCall
                              + QString(clsDebugService::msccBrktOpen)
                              + QString(clsDebugService::msccBrktClose)
                              + QString(clsXMLnode::msccScriptFunctionTerminator));
                 if ( strScriptWithCall.endsWith(clsXMLnode::msccScriptFunctionTerminator) != true ) {
                     strScriptWithCall += clsXMLnode::msccScriptFunctionTerminator;
                 }
                 strScriptWithCall += strFunc;
        //Create connection to timer and script
                QMetaObject::Connection cn = QObject::connect(ptmrScript
                                                             ,&QTimer::timeout
                                                             ,[pobjScriptEng
                                                              ,ptmrScript
                                                              ,strFile
                                                              ,strFunc
                                                              ,strScriptWithCall]() {
                     QJSValue objResult(pobjScriptEng->evaluate(strScriptWithCall));
                     QString strError;
                     if ( objResult.isError() == true ) {
                         strError = QString("%1\n%2\n%3").arg(strFile).arg(strFunc)
                                                         .arg(objResult.toString());
                     } else {
                         QString strResult(objResult.toString());
                         if ( strResult.compare("undefined") != 0 ) {
                             strError = strResult;
                         }
                     }
                     if ( strError.isEmpty() != true ) {
                         clsXMLnode* pobjRoot(clsXMLnode::spobjGetRoot());
                         emit pobjRoot->error(strError);
                         ptmrScript->deleteLater();
                     }
                });
        //Start the timer
                ptmrScript->start(cuintInterval);
            }
        }
    }
    

    In my JavaScript I call the C++ function:

    xmleng.createTimer("t1", 50, "simon2.js@testTimer");
    

    The JavaScript lambda function, it doesn't get called because the slot doesn't get called:

    function testTimer() {
        //All properties area stored as strings, convert to integer
        var intStageCtr = parseInt(xmleng.getProperty(cstrFormTest, cstrStageCtr));	
        xmleng.log(0, "testTimer[" + intStageCtr + "]", cstrThis, 316);
        //Increment stage counter
        intStageCtr++;
        //Convert back to string and store
        xmleng.setProperty(cstrFormTest, cstrStageCtr, String(intStageCtr));
    }
    

  • Moderators

    Put a breakpoint in clsMainWnd::ptmrGetTimer and confirm it gets triggered (the breakpoint).

    Additionally provide its source, and finally add this to the very beginning of the mentioned function:

    qDebug() << QThread::currentThread();
    


  • @kshegunov , I've stepped through this logic, I expect the initial call to ptmrGetTimer to return nullptr as on first call the timer won't be registered which it isn't. I've stepped through the logic to the line:

    ptmrScript->start(cuintInterval);
    

    No issues except the slot isn't called when the timer expires. And the mentioned debug output.


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    @kshegunov , I've stepped through this logic, I expect the initial call to ptmrGetTimer to return nullptr as on first call the timer won't be registered which it isn't.

    I requested something very specific with a very specific purpose. Please do what I asked and provide the output of the mentioned qDebug call.



  • @kshegunov Adding this now. I've actually changed the code to add:

    QThread* pobjCurrThread(QThread::currentThread());
    //Create new timer
    ptmrScript = new QTimer();
    ptmrScript->moveToThread(pobjCurrThread);
    qdbg() << "pobjCurrThread: " << pobjCurrThread;
    

    Output:

    pobjCurrThread: QThread(0x600000269c80)
    

    I have a breakpoint in the lambda function, first line, it doesn't get triggered.


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    I have a breakpoint in the lambda function, first line, it doesn't get triggered.

    I don't expect it to get trigerred, but again, this is not what I wrote. Here's a reminder:

    Put a breakpoint in clsMainWnd::ptmrGetTimer and confirm it gets triggered (the breakpoint).

    Additionally provide its source, and finally add this to the very beginning of the mentioned function:
    [snip]



  • @kshegunov , here is there requested source to the function:

    /**
     * @brief clsMainWnd::ptmrGetTimer
     * @param crstrID : Constant reference to ID to look-up timer
     * @return A pointer to the timer or nullptr if not found
     */
    QTimer* clsMainWnd::ptmrGetTimer(const QString& crstrID) {
        mpTimers::iterator itTimer(mmpTimers.find(crstrID));
        QTimer* pTimer(nullptr);
        if ( itTimer != mmpTimers.end() ) {
            pTimer = itTimer->second;
        }
        return pTimer;
    }
    

    I put breakpoint on first line of this, it does what I expected, nullptr is returned because on the first call the timer hasn't been registered.



  • @kshegunov , this is the modified source:

                QThread* pobjCurrThread(QThread::currentThread());
        //Create new timer
    qdbg() << "Before Timer creation: " << pobjCurrThread;
                ptmrScript = new QTimer(pobjCurrThread);
        //Register the new timer using the supplied ID
                pAppInstance->registerTimer(ptmrScript, crstrID);
        //Add any globals to the script
                clsScriptHelper::pobjGetInstance()->addGlobals(pobjScriptEng);
        //Build up script function call
                QString strFile(slstScript[SFF_FILE_IDX])
                       ,strCall(slstScript[SSF_FUNCTION_IDX])
                       ,strScriptWithCall(strScript)
                       ,strFunc(strCall
                              + QString(clsDebugService::msccBrktOpen)
                              + QString(clsDebugService::msccBrktClose)
                              + QString(clsXMLnode::msccScriptFunctionTerminator));
                 if ( strScriptWithCall.endsWith(clsXMLnode::msccScriptFunctionTerminator) != true ) {
                     strScriptWithCall += clsXMLnode::msccScriptFunctionTerminator;
                 }
                 strScriptWithCall += strFunc;
        //Create connection to timer and script
    qdbg() << "Before QObject::connect: " << QThread::currentThread();
    

    And the resulting output in debug:

    Before Timer creation: QThread(0x60000026c140)
    S000000000029E000000010940T08:43:44.084W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QThread(0x60000026c140), parent's thread is QThread(0x600000004180), current thread is QThread(0x60000026c140)
    S000000000030E000000010940T08:43:44.084DL00000661F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Before QObject::connect: QThread(0x60000026c140)
    


  • @SPlatten , I've reduced the source to just:

                QJSEngine* pobjScriptEng(clsJSON::pobjGetScriptEng());
                QThread* pobjCurrThread(QThread::currentThread());
        //Create new timer
    qdbg() << "Before Timer creation: " << pobjCurrThread;
                ptmrScript = new QTimer(pobjCurrThread);
        //Create connection to timer and script
    qdbg() << "Before QObject::connect: " << QThread::currentThread();
    
    

    And the output is still:

    Before Timer creation: QThread(0x600000264a00)
    S000000000029E000000000768T08:50:01.847W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QThread(0x600000264a00), parent's thread is QThread(0x6000000042c0), current thread is QThread(0x600000264a00)
    S000000000030E000000000768T08:50:01.847DL00000661F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Before QObject::connect: QThread(0x600000264a00)
    


  • @kshegunov , another attempt:

                QThread* pobjCurrThread(QThread::currentThread());
        //Create new timer
    qdbg() << "Before Timer creation: " << pobjCurrThread;
                ptmrScript = new QTimer;
                ptmrScript->moveToThread(pobjCurrThread);
        //Create connection to timer and script
    qdbg() << "Before QObject::connect: " << QThread::currentThread();
    

    Output:

    Before Timer creation: QThread(0x600000264d00)
    S000000000029E000000000717T08:52:29.017DL00000662F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Before QObject::connect: QThread(0x600000264d00)
    

    Not seeing any errors in the debug, but execution isn't stopping in lambda either.


  • Moderators

    Hold your horses! You have managed to confuse me about what's modified and what goes in which function. In any case in the last piece of code; after this:

    //Create new timer
    qdbg() << "Before Timer creation: " << pobjCurrThread;
                ptmrScript = new QTimer(pobjCurrThread);
        //Register the new timer using the supplied ID
    

    adding

    Q_ASSERT(clsJSON::pobjGetScriptEng()->currentThread() == QThread::currentThread());
    

    should get tripped.

    PS.
    This does nothing:

    ptmrScript = new QTimer;
    ptmrScript->moveToThread(pobjCurrThread);
    


  • @kshegunov said in Help with timer and JavaScript slot.:

    Q_ASSERT(clsJSON::pobjGetScriptEng()->currentThread() == QThread::currentThread());

    I cannot call currentThread() from pobjGetScriptEng(), it returns a pointer to QJSEngine.


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    I cannot call currentThread() from pobjGetScriptEng(), it returns a pointer to QJSEngine.

    Correct. I meant to write:

    Q_ASSERT(clsJSON::pobjGetScriptEng()->thread() == QThread::currentThread());
    


  • @kshegunov , realised that after posting, modified output to:

    qdbg() << "Script Eng Thread: " << pobjScriptEng->thread();
    qdbg() << "Before Timer creation: " << pobjCurrThread;
    

    Result is:

    S000000000028E000000000784T09:03:45.243DL00000642F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Script Eng Thread: QThread(0x60000000c0d0)
    S000000000029E000000000784T09:03:45.243DL00000643F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Before Timer creation: QThread(0x60000026f260)
    S000000000030E000000000784T09:03:45.243W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is clsScriptHelper(0x600000208d80), parent's thread is QThread(0x60000000c0d0), current thread is QThread(0x60000026f260)
    S000000000031E000000000784T09:03:45.244DL00000664F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Before QObject::connect: QThread(0x60000026f260)
    


  • @kshegunov , have now changed code to:

    ptmrScript = new QTimer(this);
    ptmrScript->moveToThread(pobjScriptEngThread);
    ptmrScript->setInterval(cuintInterval);
    

    Output is now different:

    setupForm() !!!!
    S000000000028E000000000716T09:06:20.132W:QObject: Cannot create children for a parent that is in a different thread.
    (Parent is clsScriptHelper(0x600000202820), parent's thread is QThread(0x600000004150), current thread is QThread(0x60000025e1c0)
    S000000000029E000000000716T09:06:20.132W:QObject::startTimer: Timers cannot be started from another thread
    S000000000030E000000000716T09:06:20.132DL00000688F../clsScriptHelper.cpp[void clsScriptHelper::createTimer]
    Is timer active: true
    S000000000031E000000000716T09:06:20.132DL00000207Fsimon2.js[void clsScriptHelper::log]
    setupForm() !!!!
    

    I will add another API function to allow the script to start the timer.



  • @SPlatten said in Help with timer and JavaScript slot.:

    Cannot create children for a parent that is in a different thread.

    You still have this. Excuse my complete guesswork, but do you need to go new QTimer(); rather than new QTimer(this); to move to another thread? (I have never been sure which statement causes the error message, which you can discover by stepping over or putting in qDebug() markers.)

    But if all this is beyond me and being solved by @kshegunov please ignore me --- I'm just watching the discussion :)


  • Moderators

    Right, so now comes the million bucks question(s):

    Why is clsScriptHelper::createTimer called from thread different from the one pobjScriptEng has affinity for?
    Why do you need to use threads to begin with?

    As for the "solution":

    QMetaObject::Connection cn = QObject::connect(ptmrScript
                                                             ,&QTimer::timeout
    

    Shall provide a context object for the execution. Looking at the body, I'd say it should be something like:

    QMetaObject::Connection cn = QObject::connect(ptmrScript , &QTimer::timeout, pobjScriptEng
                                                             ,[pobjScriptEng
                                                              ,ptmrScript
                                                              ,strFile
                                                              ,strFunc
                                                              ,strScriptWithCall]() {
    

    Also the timer should be created with the correct affinity, I assume:

    ptmrScript = new QTimer(pobjScriptEng);
    

    The original questions stand notwithstanding

    PS: You have race conditions all over the place ...



  • @kshegunov , createTimer is called by JavaScript:

    function setupForm() {
    	//Query all people	  
    	xmleng.log(0, "setupForm() !!!!", cstrThis, 202);
    	//Create request counter property
    	xmleng.setProperty(cstrFormTest, cstrStageCtr, "0");
    	//Create timer to issue SQL requests
    	xmleng.createTimer("t1", 50, "simon2.js@testTimer");
    	xmleng.log(0, "setupForm() !!!!", cstrThis, 207);
    	xmleng.startTimer("t1");
    };
    
    


  • @kshegunov , I've modified my source to:

     QMetaObject::Connection cn = QObject::connect(ptmrScript
                                                  ,&QTimer::timeout
                                                  ,pobjScriptEng
                                                  ,[pobjScriptEng
                                                   ,ptmrScript
                                                   ,strFile
                                                   ,strFunc
                                                   ,strScriptWithCall]() {
    

    still getting:

    S000000000027E000000000747T09:17:30.915DL00000202Fsimon2.js[void clsScriptHelper::log]
    setupForm() !!!!
    S000000000028E000000000747T09:17:30.915DL00000207Fsimon2.js[void clsScriptHelper::log]
    setupForm() !!!!
    S000000000029E000000000747T09:17:30.915W:QObject::startTimer: Timers cannot be started from another thread
    

  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    still getting

    Did you also parent the timer to the QJSEngine?



  • @kshegunov, this is how it is now:

    QJSEngine* pobjScriptEng(clsJSON::pobjGetScriptEng());
    QThread* pobjScriptEngThread(pobjScriptEng->thread());
    //Create new timer
    ptmrScript = new QTimer();
    ptmrScript->moveToThread(pobjScriptEngThread);
    ptmrScript->setInterval(cuintInterval);
    

    Have just modified to:

    QJSEngine* pobjScriptEng(clsJSON::pobjGetScriptEng());
    QThread* pobjScriptEngThread(pobjScriptEng->thread());
    //Create new timer
    ptmrScript = new QTimer();
    ptmrScript->setParent(pobjScriptEng);
    ptmrScript->moveToThread(pobjScriptEngThread);
    ptmrScript->setInterval(cuintInterval);
    

    Output is still:

    S000000000027E000000000743T09:24:17.520DL00000202Fsimon2.js[void clsScriptHelper::log]
    setupForm() !!!!
    S000000000028E000000000743T09:24:17.520W:QObject::setParent: Cannot set parent, new parent is in a different thread
    S000000000029E000000000743T09:24:17.520DL00000207Fsimon2.js[void clsScriptHelper::log]
    setupForm() !!!!
    


  • @SPlatten
    Perhaps not relevant, but how can you go

                ptmrScript->moveToThread(pobjScriptEngThread);
                ptmrScript->setInterval(cuintInterval);
    

    Once moved to other thread, are you still allowed to set its interval from this (different) thread?


  • Moderators

    Okay, I'm getting really tangled. Where is QTimer::start called? In createTimer? If so, then:

    QTimer timer = new QTimer();
    ...
    // Connect the lambda with a context object, as mentioned!
    ...
    timer->start();
    


  • @kshegunov , I'm trying lots of things without taking the time to think about it.


  • Moderators

    @SPlatten said in Help with timer and JavaScript slot.:

    I'm trying lots of things without taking the time to think about it.

    Yes, do so. Which is the whole reason I requested the call stack. How am I supposed to guess what calls what ...



  • @kshegunov I would provide the call stack, but execution doesn't halt, so where would you like me to break to then get the stack?



  • @SPlatten I am always surprised how complicated you are trying to solve common issues.

    What is the real issue here?
    You want to create a timer in a specific thread and start it. I am right?
    QTimer muss be started, and stopped from the owned thread.
    That's not so complicated to solve:

    auto myTimer = new  QTimer();
    connect(myTimer; &QTimer::timeout, ...);
    // move to thread
    myTimer->moveToThread(theWorkingThread);
    
    // start the timer
    QTimer::singleShot(0, myTimer, [myTimer]() { myTimer->start(); } );
    

Log in to reply