Help with timer and JavaScript slot.
-
@SPlatten said in Help with timer and JavaScript slot.:
still getting
Did you also parent the timer to the
QJSEngine
?wrote on 30 Dec 2021, 09:21 last edited by SPlatten@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() !!!!
-
@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() !!!!
wrote on 30 Dec 2021, 09:24 last edited by@SPlatten
Perhaps not relevant, but how can you goptmrScript->moveToThread(pobjScriptEngThread); ptmrScript->setInterval(cuintInterval);
Once moved to other thread, are you still allowed to set its interval from this (different) thread?
-
@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() !!!!
Okay, I'm getting really tangled. Where is
QTimer::start
called? IncreateTimer
? If so, then:QTimer timer = new QTimer(); ... // Connect the lambda with a context object, as mentioned! ... timer->start();
-
Okay, I'm getting really tangled. Where is
QTimer::start
called? IncreateTimer
? If so, then:QTimer timer = new QTimer(); ... // Connect the lambda with a context object, as mentioned! ... timer->start();
wrote on 30 Dec 2021, 09:27 last edited by@kshegunov , I'm trying lots of things without taking the time to think about it.
-
@kshegunov , I'm trying lots of things without taking the time to think about it.
@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 ...
-
@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 ...
wrote on 30 Dec 2021, 09:31 last edited by@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?
-
@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() !!!!
wrote on 30 Dec 2021, 09:32 last edited by KroMignon@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(); } );
-
@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(); } );
wrote on 30 Dec 2021, 09:33 last edited by SPlatten@KroMignon , thank you, will try this now, right now before trying your suggestion the output is:
S000000000027E000000000715T09:32:03.904DL00000202Fsimon2.js[void clsScriptHelper::log] setupForm() !!!! S000000000028E000000000715T09:32:03.904DL00000207Fsimon2.js[void clsScriptHelper::log] setupForm() !!!! S000000000029E000000003405T09:32:06.594W:QObject::startTimer: Timers cannot be started from another thread
@KroMignon, thank you so much, this now works, here are the prototypes:
Q_INVOKABLE void createTimer(const QString& crstrID, const uint cuintInterval ,const QString& crstrFunction); Q_INVOKABLE void startTimer(const QString& crstrID);
And the final implementations:
/** * @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(); ptmrScript->setInterval(cuintInterval); //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 ,[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(); } }); QThread* pobjScriptEngThread(pobjScriptEng->thread()); ptmrScript->moveToThread(pobjScriptEngThread); } } } /** * @brief clsScriptHelper::startTimer * @param crstrID : Constant reference to timer ID */ void clsScriptHelper::startTimer(const QString& crstrID) { //Get Application instance clsMainWnd* pAppInstance(clsMainWnd::pobjGetAppWnd()); if ( pAppInstance == nullptr ) { //Cannot get application instance! return; } QTimer* ptmrScript(pAppInstance->ptmrGetTimer(crstrID)); if ( ptmrScript != nullptr ) { QTimer::singleShot(0, ptmrScript, [ptmrScript]() { ptmrScript->start(); } ); } }
-
@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 said in Help with timer and JavaScript slot.:
I would provide the call stack, but execution doesn't halt, so where would you like me to break to then get the stack?
Before doing the connect for the timer timeout. Provide the following things (in one post please):
- The whole source of the enclosing function.
- The call stack.
- The output of this added just before doing the connect:
qDebug() << ptmrScript->thread() << QThread::currentThread() << ptmrScript->parent();
-
@KroMignon , thank you, will try this now, right now before trying your suggestion the output is:
S000000000027E000000000715T09:32:03.904DL00000202Fsimon2.js[void clsScriptHelper::log] setupForm() !!!! S000000000028E000000000715T09:32:03.904DL00000207Fsimon2.js[void clsScriptHelper::log] setupForm() !!!! S000000000029E000000003405T09:32:06.594W:QObject::startTimer: Timers cannot be started from another thread
@KroMignon, thank you so much, this now works, here are the prototypes:
Q_INVOKABLE void createTimer(const QString& crstrID, const uint cuintInterval ,const QString& crstrFunction); Q_INVOKABLE void startTimer(const QString& crstrID);
And the final implementations:
/** * @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(); ptmrScript->setInterval(cuintInterval); //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 ,[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(); } }); QThread* pobjScriptEngThread(pobjScriptEng->thread()); ptmrScript->moveToThread(pobjScriptEngThread); } } } /** * @brief clsScriptHelper::startTimer * @param crstrID : Constant reference to timer ID */ void clsScriptHelper::startTimer(const QString& crstrID) { //Get Application instance clsMainWnd* pAppInstance(clsMainWnd::pobjGetAppWnd()); if ( pAppInstance == nullptr ) { //Cannot get application instance! return; } QTimer* ptmrScript(pAppInstance->ptmrGetTimer(crstrID)); if ( ptmrScript != nullptr ) { QTimer::singleShot(0, ptmrScript, [ptmrScript]() { ptmrScript->start(); } ); } }
wrote on 30 Dec 2021, 09:37 last edited by@SPlatten said in Help with timer and JavaScript slot.:
right now before trying your suggestion the output is:
setupForm() !!!! S000000000029E000000003405T09:32:06.594W:QObject::startTimer: Timers cannot be started from another thread
Same issue, you are trying to start a QTimer from the wrong thread.
QTimer::singleShot(0, myTimer, [myTimer]() { myTimer->start(); } );
will solve this.
43/43