Pergunta

I've recently add a script function on a simulator. I've add a "Launch Script" button on the GUI, who is able to launch the evaluation of a script.

My main creates a QThread (scriptThread) who evaluate my script. My QMainWindows send signals to my main, who call scriptThread slots.

I want to be able to start, and stop the script when I want from the GUI. I've first called terminate() slots of the scriptThread. But it destroy my Qthread, and I'm not able to relunch the script after canceling it (because I've created my scriptThread on the start of my main).

This is a part of my main :

MyGUI w();
ScriptThread scriptThread();

QObject::connect(&w, SIGNAL(setScriptPath(QString)),
               &scriptThread, SLOT(setPath(QString)));
QObject::connect(&w, SIGNAL(launchScriptSignal()),
               &scriptThread, SLOT(start()));
QObject::connect(&w, SIGNAL(stopScript()),
               &scriptThread, SLOT(terminate()));

QObject::connect(&scriptThread, SIGNAL(finished()),
               &w, SLOT(scriptFinished()));

This is my run() function in my scriptThread :

QScriptEngine m_scriptEngine;
QScriptValue m_result;

QScriptValue m_scriptValue = m_scriptEngine.newQObject(m_MyQOBJECT);

m_scriptEngine.globalObject().setProperty("sc", m_scriptValue); 

QFile file(m_path);
bool result = file.open(QIODevice::ReadOnly); 

if(!result)
{
  printf("Script path not found.\n");
  emit finished();
  return;
} 

m_result = m_scriptEngine.evaluate(file.readAll());

if(m_result.toString() != "undefined")
  std::cout << m_result.toString().toStdString() << std::endl;

file.close();

if(m_scriptEngine.hasUncaughtException()) 
{
  int lineNo = m_scriptEngine.uncaughtExceptionLineNumber();
  printf("lineNo : %i\n", lineNo);
}

printf("ScriptThread finished\n");
emit finished();

The GUI interesting functions :

void myGUI::launchScript(QString path)
{
  if(!m_isScriptRunning)
  {    
    path = ui->editScriptPath->text();
    disableAll();

    ui->Script->setText("stop script");
    m_isScriptRunning = true ;

    emit setScriptPath(path);  
    emit launchScriptSignal();  
  }
  else
  {
    emit stopScript();
    scriptFinished();
  }
}

void MyGUI::scriptFinished()
{
  enableAll();

  ui->Script->setText("launch script");
  m_isScriptRunning = false ;
}

So my question is, how can I cancel the evaluation of my script, without destructing the thread ? I've tried the quit() slot, but it's only for event loop. Is there an existing slot or a litle trick to do that ?

Thanks.

Foi útil?

Solução 2

I've succefuly tried Kamil solution.

In Qt 4.4 and superior, there is a QScriptEngine::abortEvaluation() function who is working great.

I've just switch my engine who was local to my function into my class.

Working part code of ScriptThread.cpp :

void ScriptThread::cancelScriptEvaluation()
{
  m_scriptEngine.abortEvaluation();
  emit finished();
}

With of course in the ScriptThread.h :

private:
  QScriptEngine m_scriptEngine;

And in my main :

QObject::connect(&w, SIGNAL(stopScript()),
               &scriptThread, SLOT(cancelScriptEvaluation()));

Outras dicas

abortEvaluation() doesn't work for QScriptValue::call() nor calls from C++ code to javascript. To interrupt those, you can throw an exception. This worked for me and I'm putting it here so nobody else has to spend the time looking for it:

if(engine->isEvaluating())
{
    engine->abortEvaluation();
}
else
{
    QScriptContext *ctx = engine->currentContext();
    if(ctx)
        ctx->throwError("Code has been executing for too long!");
}

Of course, the script can catch this exception and continue, there is a pretty good chance it won't though, and even if it does, it is likely to get out of the infinite loop.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top