注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

沙漠里de烟雨

原创分享,禁止转载

 
 
 

日志

 
 

Qt C++如何运行javascript脚本  

2017-10-03 14:32:30|  分类: QT5.x与QML |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
最近因项目的需要,封装了一个qt c++可调用js脚本的类,可实现诸如金融交易策略的策略编写。当然可以更多的用途,现在就把代码贴上:
JSEngine.pro ==>

QT += core gui qml

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = JSEngine
TEMPLATE = app

DESTDIR += $$PWD/bin64

SOURCES += main.cpp\
        widget.cpp \
    jswork.cpp

HEADERS  += widget.h \
    jswork.h


//记得要加上qml这个模块

下面就是关键的代码,JSWork类:
jswork.h ==>

#ifndef JSWORK_H
#define JSWORK_H
#include <QObject>
#include <QJSEngine>
#include <QJSValue>
#include <QHash>
class JSWork : public QObject
{
    Q_OBJECT
public:
    explicit JSWork(QObject *parent = nullptr);
public:
    QJSEngine* JsEngine() const;
    bool DeleteGlobalObjectByName(const QString& objectNameInJs); //从引擎globalObject中删除全局对象,但如果在js中引用如了(如:删除了"GlobalSum",但在js中GlobalSum = 55,则被认为其为全局变量(未声明),此时又加入了globalObject中,除非不再用;)
    bool AppendGlobalQObjectIntoEngine(const QString& objectNameInJs, QObject* object);//向引擎中添加对象类型的全局对象;
    bool AppendGlobalValueIntoEngine(const QString& valueNameInJs, QJSValue value); //向JS代码中添加全局对象;
    void UpdateGlobalValueOfEngine(const QString& valueNameInJs, QJSValue value); //设置JS代码中全局对象的值;
    QJSValue LoadJSFileIntoEngine(const QString& jsFile); //加载JS代码文件至引擎中,加载后一直可用(建议只加载一次即可);
    QJSValue InvokeJSFunctionName(const QString& jsFunctionName,bool hasReturnValue=true, const QJSValueList& args=QJSValueList()); //通过函数名(js文件中的函数名),以及参数列表调用js函数并获取返回值;
    QJSValue GlobalObject2JSValue(const QString& objectNameInJs);//返回jsValue类型的对象(包括QObject转JSValue对象);
    QObject* GlobalObject2QObject(const QString& objectNameInJs); //只返回QObject类型的对象;
    QJSValue GlobalObjectPropertyValue(const QString& objectNameInJs, const QString& property); //通过全局对象名获取对象的属性值;
    QJSValue GlobalObjectFunctionCall(const QString& objectNameInJs, const QString& functionName,bool hasReturnValue=true, const QJSValueList& args=QJSValueList()); //根据全局对象名,给成员函数传入参数并调用其函数方法并获取返回值;
    QJSValue InvokeJSFunctionContent(const QString& jsFunctionContent,bool hasReturnValue=true, const QJSValueList& args=QJSValueList()); //通过函数定义的内容字串,以及参数列表调用函数并获取返回值;此js代码临时可用,不会加载到引擎中;
    QJSValue InvokdeJSExpression(const QString& jsExpression); //通过传入的语句表达式来返回值;此js代码临时可用,不会加载到引擎中;
private:
    bool isValid(const QJSValue &result);
    bool isValidValue(const QJSValue& result);
    bool isGlobalObjectContains(const QString &objectNameInJs);
private:
    QJSEngine*                  m_jsEngine;
};
#endif // JSWORK_H


jswork.cpp ===>

#include "jswork.h"
#include <QFile>
#include <QTextStream>
#include <QDebug>

JSWork::JSWork(QObject *parent) : QObject(parent)
{
    m_jsEngine = new QJSEngine(this);
    m_jsEngine->installExtensions(QJSEngine::AllExtensions); //js中可使用console,qsTr,等;
}
QJSEngine *JSWork::JsEngine() const
{
    return m_jsEngine;
}
bool JSWork::DeleteGlobalObjectByName(const QString& objectNameInJs)
{
    return m_jsEngine->globalObject().deleteProperty(objectNameInJs);
}
bool JSWork::AppendGlobalQObjectIntoEngine(const QString &objectNameInJs, QObject *object)
{
    if(!object || objectNameInJs.isEmpty())
    {
        qDebug() << "object is null or objectNameInJs is empty!" << endl;
        return false;
    }
    if(m_jsEngine->globalObject().hasProperty(objectNameInJs))
    {
        qDebug() << "the " << objectNameInJs << " already been has!" << endl;
        return false;
    }
    QJSValue jsObject = m_jsEngine->newQObject(object);
    if(isValidValue(jsObject) && jsObject.isQObject())
    {
        m_jsEngine->globalObject().setProperty(objectNameInJs, jsObject);
        return true;
    }
    qDebug() << "AppendGlobalObjectIntoEngine failed!" << endl;
    return false;
}
bool JSWork::AppendGlobalValueIntoEngine(const QString &valueNameInJs, QJSValue value)
{
    if(valueNameInJs.isEmpty() || valueNameInJs.isNull())
    {
        qDebug() << "valueNameInJs is empty or null" << endl;
        return false;
    }
    if(m_jsEngine->globalObject().hasProperty(valueNameInJs))
    {
        qDebug() << "the " << valueNameInJs << " already been has!" << endl;
        return false;
    }
    m_jsEngine->globalObject().setProperty(valueNameInJs,value);
    return true;
}
void JSWork::UpdateGlobalValueOfEngine(const QString &valueNameInJs, QJSValue value)
{
    if(valueNameInJs.isEmpty() || valueNameInJs.isNull())
    {
        qDebug() << "valueNameInJs is empty or null." << endl;
        return ;
    }
    if(m_jsEngine->globalObject().hasProperty(valueNameInJs))
        m_jsEngine->globalObject().setProperty(valueNameInJs,value);
    qDebug() << "UpdateGlobalValueOfEngine failed!" << endl;
}
QJSValue JSWork::LoadJSFileIntoEngine(const QString &jsFile)
{
      QFile scriptFile(jsFile);
      if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text))
      {
          qDebug() << "jsFile: " << jsFile << " connot be opened!" << endl;
          return QJSValue();
      }
      QTextStream stream(&scriptFile);
      stream.setCodec("UTF-8");
      QString contents = stream.readAll();
      scriptFile.close();
      QJSValue jsObject = m_jsEngine->evaluate(contents, jsFile);
      if(isValid(jsObject))
          return jsObject;
      qDebug() << "LoadJSFileIntoEngine failed!" << endl;
      return QJSValue();
}
QJSValue JSWork::InvokeJSFunctionName(const QString &jsFunctionName, bool hasReturnValue, const QJSValueList &args)
{
    if(jsFunctionName.isEmpty() || jsFunctionName.isNull())
    {
        qDebug() << "jsFunctionName is empty or null" << endl;
        return QJSValue();
    }
    QJSValue jsFunc = m_jsEngine->evaluate(jsFunctionName);
    if(isValidValue(jsFunc) && jsFunc.isCallable())
    {
        QJSValue result = jsFunc.call(args);
        if(hasReturnValue ? isValidValue(result) : isValid(result))
            return result;
    }
    qDebug() << "InvokeJSFunctionName failed!" << endl;
    return QJSValue();
}
QJSValue JSWork::GlobalObject2JSValue(const QString &objectNameInJs)
{
    if(objectNameInJs.isEmpty() || objectNameInJs.isNull())
    {
        qDebug() << "objectNameInJs is empty or null." << endl;
        return QJSValue();
    }
    if(!isGlobalObjectContains(objectNameInJs))
    {
        qDebug() << "global object cannot exist this objectNameInJS:" << objectNameInJs << endl;
        return QJSValue();
    }
    QJSValue jsVal = m_jsEngine->globalObject().property(objectNameInJs);
    if(isValidValue(jsVal))
        return jsVal;
    qDebug() << "GlobalObject2JSValue failed!" << endl;
    return QJSValue();
}
QObject *JSWork::GlobalObject2QObject(const QString &objectNameInJs)
{
    QJSValue jsVal = GlobalObject2JSValue(objectNameInJs);
    if(!jsVal.isNull() && jsVal.isQObject())
        return jsVal.toQObject();
    qDebug() << "GlobalObject2Object failed!" << endl;
    return 0;
}
QJSValue JSWork::GlobalObjectPropertyValue(const QString &objectNameInJs, const QString &property)
{
    QJSValue object = GlobalObject2JSValue(objectNameInJs);
    if(isValidValue(object))
    {
        QJSValue result = object.property(property);
        if(isValidValue(result))
            return result;
    }
    qDebug() << "GlobalObjectPropertyValue failed!" << endl;
    return QJSValue();
}
QJSValue JSWork::GlobalObjectFunctionCall(const QString &objectNameInJs, const QString &functionName, bool hasReturnValue, const QJSValueList& args)
{
    QJSValue object = GlobalObject2JSValue(objectNameInJs);
    if(isValidValue(object))
    {
        QJSValue func = object.property(functionName);
        if(isValidValue(func) && func.isCallable())
        {
            QJSValue result = func.call(args);
            if(hasReturnValue?isValidValue(result):isValid(result))
                return result;
        }
    }
    qDebug() << "GlobalObjectFunctionCall failed!" << endl;
    return QJSValue();
}
QJSValue JSWork::InvokeJSFunctionContent(const QString &jsFunctionContent,bool hasReturnValue, const QJSValueList& args)
{
    if(jsFunctionContent.isEmpty() || jsFunctionContent.isNull())
    {
        qDebug() << "jsFunctionContent is empty or null." << endl;
        return QJSValue();
    }
    QString jsFunc = "("+jsFunctionContent+")";
    QJSValue res = m_jsEngine->evaluate(jsFunc);
    if(isValid(res))
    {
        QJSValue result = res.call(args);
        if(hasReturnValue?isValidValue(result):isValid(result))
            return result;
    }
    qDebug() << "InvokeJSFunctionContent failed!" << endl;
    return QJSValue();
}
QJSValue JSWork::InvokdeJSExpression(const QString &jsExpression)
{
    if(jsExpression.isEmpty() || jsExpression.isNull())
    {
        qDebug() << "jsExpression is empty or null." << endl;
        return QJSValue();
    }
    QJSValue result = m_jsEngine->evaluate(jsExpression);
    if(isValid(result))
        return result;
    qDebug() << "jsExpression failed!" << endl;
    return QJSValue();
}
bool JSWork::isValid(const QJSValue &result)
{
    if (result.isError())
    {
        qDebug()<< "Uncaught exception at line"
                << result.property("lineNumber").toInt()
                << ":" << result.toString();
        return false;
    }
    return true;
}
bool JSWork::isValidValue(const QJSValue &result)
{
    if(!isValid(result))
        return false;
    if(result.isUndefined())
    {
        qDebug() << "the result is undefined!" << endl;
        return false;
    }
    if(result.isNull())
    {
        qDebug() << "the result is null!" << endl;
        return false;
    }
    return true;
}
bool JSWork::isGlobalObjectContains(const QString &objectNameInJs)
{
    if(objectNameInJs.isEmpty() || objectNameInJs.isNull())
    {
        qDebug() << "isGlobalObjectContains : objectNameInJs is empty or null" << endl;
        return false;
    }
    QJSValue object = m_jsEngine->globalObject();
    if(isValidValue(object) && object.hasProperty(objectNameInJs))
        return true;
    return false;
}


下面是调用代码,你运行这份代码稍微细究之后,就很容易了解它的用法了:

widget.h ====>


#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QJSValue>
class JSWork;
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = 0);
    ~Widget();
private slots:
    void btnSlot1();
    void btnSlot2();
    void btnSlot3();
    void btnSlot4();
    void btnSlot5();
    void btnSlot6();
    void btnSlot7();
    void btnSlot8();
    void btnSlot9();
private:
    JSWork*     m_jsWork;
};
#endif // WIDGET_H


widget.cpp ===>


#include "widget.h"
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QCoreApplication>
#include <QDebug>
#include <QLayout>
#include <QCheckBox>
#include <QLabel>
#include "jswork.h"
Widget::Widget(QWidget *parent)  : QWidget(parent)
{
    this->resize(800,600);
    QString jsFile = QCoreApplication::applicationDirPath()+"/test.js";
    QCheckBox* chk = new QCheckBox("ck",this);
    chk->setChecked(true);
    QLabel* lab = new QLabel("hello",this);
    m_jsWork = new JSWork(this);
    m_jsWork->LoadJSFileIntoEngine(jsFile);
    m_jsWork->AppendGlobalValueIntoEngine("MONEY",100);
    m_jsWork->AppendGlobalQObjectIntoEngine("CheckBox",chk);
    m_jsWork->AppendGlobalQObjectIntoEngine("Label",lab);
    QGridLayout* layout = new QGridLayout;
    QPushButton* btn1 = new QPushButton("btn1",this);
    QPushButton* btn2 = new QPushButton("btn2",this);
    QPushButton* btn3 = new QPushButton("btn3",this);
    QPushButton* btn4 = new QPushButton("btn4",this);
    QPushButton* btn5 = new QPushButton("btn5",this);
    QPushButton* btn6 = new QPushButton("btn6",this);
    QPushButton* btn7 = new QPushButton("btn7",this);
    QPushButton* btn8 = new QPushButton("btn8",this);
    QPushButton* btn9 = new QPushButton("btn9",this);
    layout->addWidget(btn1,0,0);
    layout->addWidget(btn2,0,1);
    layout->addWidget(btn3,0,2);
    layout->addWidget(btn4,1,0);
    layout->addWidget(btn5,1,1);
    layout->addWidget(btn6,1,2);
    layout->addWidget(btn7,2,0);
    layout->addWidget(btn8,2,1);
    layout->addWidget(btn9,2,2);
    layout->addWidget(chk,3,0);
    layout->addWidget(lab,3,1);
    this->setLayout(layout);
    connect(btn1,SIGNAL(clicked()),this,SLOT(btnSlot1()));
    connect(btn2,SIGNAL(clicked()),this,SLOT(btnSlot2()));
    connect(btn3,SIGNAL(clicked()),this,SLOT(btnSlot3()));
    connect(btn4,SIGNAL(clicked()),this,SLOT(btnSlot4()));
    connect(btn5,SIGNAL(clicked()),this,SLOT(btnSlot5()));
    connect(btn6,SIGNAL(clicked()),this,SLOT(btnSlot6()));
    connect(btn7,SIGNAL(clicked()),this,SLOT(btnSlot7()));
    connect(btn8,SIGNAL(clicked()),this,SLOT(btnSlot8()));
    connect(btn9,SIGNAL(clicked()),this,SLOT(btnSlot9()));
}
Widget::~Widget()
{
}
void Widget::btnSlot1()
{
    qDebug() << m_jsWork->InvokeJSFunctionContent("function sub(){return 33;}").toInt() << endl;
    qDebug() << m_jsWork->InvokeJSFunctionContent("function sub(){return 33+MONEY;}").toInt() << endl;
}
void Widget::btnSlot2()
{
    qDebug() << m_jsWork->InvokeJSFunctionName("add",true,QJSValueList()<<5).toInt() << endl;
}
void Widget::btnSlot3()
{
    QJSValueList args;
    args << 5 << 6;
    qDebug() << m_jsWork->InvokeJSFunctionName("add2",true,args).toInt() << endl;
}
void Widget::btnSlot4()
{
    qDebug() << m_jsWork->GlobalObject2JSValue("MONEY").toInt() << endl;
    qDebug() << m_jsWork->GlobalObject2JSValue("AAA").toInt() << endl; //JS中的全局变量是可以在获取到的;
    qDebug() << m_jsWork->InvokeJSFunctionName("update").toInt() << endl;
}
void Widget::btnSlot5()
{
    m_jsWork->GlobalObjectFunctionCall("CheckBox","setChecked",false,QJSValueList()<<false);
}
void Widget::btnSlot6()
{
    qDebug() << m_jsWork->GlobalObjectPropertyValue("Label","text").toString() << endl;
    qDebug() << "sub: " << m_jsWork->InvokeJSFunctionName("sub").toInt() << endl;
    qDebug() << "sub: " << m_jsWork->InvokdeJSExpression("3+5").toInt() << endl;
    qDebug() << "sub: " << m_jsWork->InvokdeJSExpression("MONEY+5").toInt() << endl;
}
void Widget::btnSlot7()
{
    m_jsWork->InvokeJSFunctionName("setchk",false);
    QJSValue res = m_jsWork->InvokeJSFunctionName("getArr");
    if(res.isArray())
    {
        qDebug() << res.property(2).toInt() << endl;
    }
}
void Widget::btnSlot8()
{
    bool ok = m_jsWork->DeleteGlobalObjectByName("MONEY"); //当删除了一次后,如果在js中用到,如update()中,由于此时MONEY未声明,会被认为是全局变量,再次被写入globalObject中,故而后面再调用时便可以使用;
    if(ok)
        qDebug() << "delete successed!" << endl;
}
void Widget::btnSlot9()
{
    qDebug() << m_jsWork->InvokeJSFunctionName("setUndefined").toInt() << endl; //在函数中初始化未定义的变量,会被认为是全局变量,且;
    qDebug() << m_jsWork->GlobalObject2JSValue("ABC").toInt() << endl;
    qDebug() << m_jsWork->InvokeJSFunctionName("addABC",true,QJSValueList()<<2).toInt() << endl; //此时ABC可以使用;只要运行了一次setUndefined()后,ABC到处可用;
}
  评论这张
 
阅读(7)| 评论(0)
推荐

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017