停止对 Qt 脚本的评估

Stop the evaluation of a Qt Script

本文关键字:评估 脚本 Qt      更新时间:2023-10-16

我最近在模拟器上添加了一个脚本函数。我在 GUI 上添加了一个"启动脚本"按钮,该按钮能够启动脚本的评估。

我的主要创建了一个QThread(scriptThread)来评估我的脚本。我的QMainWindows向我的主服务器发送信号,后者调用scriptThread插槽。

我希望能够启动脚本,并在需要时从 GUI 停止脚本。我首先调用了 scriptThread 的 terminate() 插槽。但是它破坏了我的 Qthread,取消脚本后我无法重新编写脚本(因为我在 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()));

这是我的脚本线程中的 run() 函数:

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 : %in", lineNo);
}
printf("ScriptThread finishedn");
emit finished();

GUI有趣的功能:

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 ;
}

所以我的问题是,如何在不破坏线程的情况下取消脚本的评估?我已经尝试了 quit() 插槽,但它仅用于事件循环。是否有现有的插槽或技巧可以做到这一点?

谢谢。

abortEvaluation()不适用于

QScriptValue::call(),也不适用于从C++代码到javascript的调用。要中断这些,您可以引发异常。这对我有用,我把它放在这里,所以没有其他人需要花时间寻找它:

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

当然,脚本可以捕获此异常并继续,但很有可能它不会,即使它这样做,它也很可能会脱离无限循环。

我已经成功尝试了卡米尔解决方案。

在Qt 4.4及更早版本中,有一个QScriptEngine::abortEvaluation()函数工作得很好。

我刚刚将我的函数本地引擎切换到我的类中。

脚本线程的工作部分代码.cpp

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

当然在 ScriptThread.h 中:

private:
  QScriptEngine m_scriptEngine;

在我的主要:

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