3

我最近在模拟器上添加了一个脚本功能。我在 GUI 上添加了一个“启动脚本”按钮,它能够启动脚本的评估。

我的 main 创建了一个 QThread (scriptThread) 来评估我的脚本。我的 QMainWindows 向调用 scriptThread 插槽的主发送信号。

我希望能够在需要时从 GUI 启动和停止脚本。我首先调用了 scriptThread 的 terminate() 插槽。但它破坏了我的 Qthread,并且在取消它后我无法重新启动脚本(因为我已经在我的 main 开始时创建了我的 scriptThread)。

这是我主要的一部分:

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()));

这是我 scriptThread 中的 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 : %i\n", lineNo);
}

printf("ScriptThread finished\n");
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() 插槽,但它仅用于事件循环。是否有现有的插槽或小技巧可以做到这一点?

谢谢。

4

2 回答 2

1

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!");
}

当然,脚本可以捕捉到这个异常并继续,但很有可能它不会,即使它捕捉到了,它也很可能会跳出无限循环。

于 2014-12-08T23:59:30.357 回答
0

我已经成功尝试了 Kamil 解决方案。

在 Qt 4.4 及更高版本中,有一个 QScriptEngine::abortEvaluation() 函数运行良好。

我刚刚将我的功能本地的引擎切换到我的班级。

ScriptThread.cpp 的工作部分代码:

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

当然在 ScriptThread.h 中:

private:
  QScriptEngine m_scriptEngine;

在我的主要内容中:

QObject::connect(&w, SIGNAL(stopScript()),
               &scriptThread, SLOT(cancelScriptEvaluation()));
于 2014-01-08T14:42:06.200 回答