zoukankan      html  css  js  c++  java
  • Qt---Javascript/Qt交互、脚本化

    Qt提供了对Javascript的良好支持, 如果查阅过文档你就知道Qt有两个不同的Js封装引擎:

    • QScriptEngine
    • QJSEngine

    QScriptEngine出现的比较早(自Qt4.3始),基于WebKit的JavaScriptCore引擎,提供的api相对来说比较丰富,但是已经被官方标注为deprecated;QJSEngine则是从Qt5.0开始提供,基于谷歌的V8引擎,是官方建议使用的版本。至于为什么QScriptEngine会被Qt废弃,各种原因就比较复杂了,有兴趣的朋友可以看这个链接,我这里简要概括讲一下Qt js模块的实现历史及原因:

    1. QScriptEngine---使用自建的js引擎:功能落后、运行非常慢
    2. QScriptEngine---使用JavaScriptCore引擎(WebKit的主引擎):
      • 由此封装提供的JS API暴露了实现细节
      • 由于设计使用方式的不同一些原有函数无法实现(例如QScriptContext)
      • JavaScriptCore变化太大,没有一个稳定的API来供QtScript实现想要的功能,每一次引擎的变化都需要QtScript模块内部进行大的调整。
    3. QScriptEngine---使用V8引擎:V8对外提供的API稳定可嵌入到程序中;但是V8与JavaScriptCore内部细节不同,QtScript API的某些概念无法自然映射到V8上,用V8实现相同性能的旧接口需要相当大的投入,然而QML团队无法接受这样的投入花费。
    4. QJSEngine-------使用V8引擎。

    1. QScriptEngine VS QJSEngine

    从两个主要的引擎类上来说,相比QScriptEngine,虽然QJSEngine出来的迟,但是核心的功能(加粗)也是支持的,仅在其他一些小功能上有所欠缺(未加粗):

    • 执行脚本字符串。
    • 引擎全局变量配置。
    • 异常处理。
    • Js对象创建
    • Qt类与Js的交互集成。
    • Js扩展。
    • 自定义C++类(非Qt内建)。
    • C++函数与Js的交互集成。
    • Long-running脚本优化处理。
    • 调试跟踪。

    但是毕竟对JavaScriptCore引擎的封装比较成熟,从QScriptEngine衍生出的技术支持肯定是比较丰富,使用也较为方便。例如QtScript模块同时包含QScriptClassPropertyIterator类来提供java风格的属性遍历功能、QScriptContext类来提供上下文信息,等等。但是随着Qt新版本的发布,QJsEngine肯定是越来越成熟的。需要注意的是,这两个应该都不能与Qt的Web模块交互使用(亲测QJSEngine与QWebEngineView交互无效),毕竟都分成了两个不同的模块。

    2. QJSEngine介绍

    这里我们简单学习QJSEngine,一如既往,我们通过一个小例子来学习当前js引擎提供的主要功能, 实际上使用非常简单。

    2.1 执行脚本

    QJSValue QJSEngine::evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1)

    我们只需要把包含js代码的字符串传给 QJSEngine::evaluate()这个函数,就可以直接执行该js代码。该函数的后两个参数是可选的文件名和行号,会在js出错的时候包含在出错信息里。示例程序中当用户点击执行按钮,我们直接就执行用户输入的js代码:

    void MainWindow::on_buttonEvaluateJs_clicked(bool)
    {
        ui->lineEditJsResult->setText(
                    m_jsEngine.evaluate(ui->lineEditEvaluateJs->text()).toString());
        ui->lineEditJsResult->setEnabled(ui->buttonEvaluateJs->isEnabled());
    }
    

    evaluate-js

    2.2 配置引擎的全局变量(C++/Js交互)

    QJSValue QJSEngine::globalObject() const
    QJSValue QJSEngine::newObject()
    void QJSValue::setProperty(const QString &name, const QJSValue &value)

    通过globalObject()函数我们获得Js引擎的全局变量,这个变量是一个QJSValue,是Qt对Js数据类型的一个封装,基本上支持所有Js对象的操作。例如,我们可以判断两个QJSValue是否相等、是否严格相等、设置属性、设置原型等。全局对象就是一个可以在Js代码中直接使用的Js变量,通常我们做的就是在C++代码里设置全局变量的属性,然后在Js中直接使用。

    newObject()函数用来新建一个Js对象,示例中我们在新建的Js对象上分别设置3个属性(setProperty())为用户输入的左操作数、右操作数和运算符,然后把这个对象设置为全局对象的一个属性,接着我们在Js代码中直接调用这3个属性来进行计算:

    void MainWindow::on_buttonEvaluatePropertyCalculateResult_clicked(bool)
    {
        auto jsObject = m_jsEngine.newObject();
        jsObject.setProperty("leftOperand", ui->lineEditPropertyLeft->text());
        jsObject.setProperty("rightOperand", ui->lineEditPropertyRight->text());
        m_jsEngine.globalObject().setProperty("cppObject", jsObject);
    
        ui->lineEditEvaluatePropertyResult->setText(m_jsEngine.evaluate(
            "cppObject.leftOperand" +
            ui->lineEditPropertyOperator->text() +
            "cppObject.rightOperand").toString());
        ui->lineEditEvaluatePropertyResult->setEnabled(
            ui->buttonEvaluatePropertyCalculateResult->isEnabled());
    }
    

    calculate-js

    2.3 Qt/Js交互(脚本化)

    QJSValue newQObject(QObject *object)

    Signals and slots, properties and children of object are available as properties of the created QJSValue.

    通过newQObject()这个函数,我们可以将Qt类封装成Js对象,集成到Js引擎中。Qt类的信号槽属性子对象可以在Js中通过属性来使用,Qt提供强大的本地功能支持,Js提供灵活的使用方式,想想就很激动。我们可以借此在Js中操控导出的Qt对象、更改界面外观、实现程序功能的脚本化。

    示例中我们导出街面上的一个QPushButton,把它设置为Js引擎全局对象的一个属性:

    m_jsEngine.globalObject().setProperty("cppButton", m_jsEngine.newQObject(ui->buttonChangeInJs));
    

    当用户点击这个按钮的时候,我们读取本地的Js文件到QString中并执行这段代码,该Js代码会调用setStyleSheet()函数(注意这是一个slot)来更改这个按钮的外观样式:

    void MainWindow::on_buttonChangeInJs_clicked(bool)
    {
        QFile jsFile(":/js/demo.js");
        if (jsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
            auto jsStr = QString::fromStdString(jsFile.readAll().toStdString());
            auto jsResult = m_jsEngine.evaluate(jsStr);
    
            if (jsResult.isError())
                ui->buttonChangeInJs->setText(jsResult.toString());
        }
    }
    
    function func() {
        cppButton.setStyleSheet('QPushButton { background-color: qlineargradient(
                                                    x0:0, y0:0, x1:1, y1:1, 
                                                    stop: 0.0 #111111,
                                                    stop: 0.2 #222222,
                                                    stop: 0.4 #444444,
                                                    stop: 0.6 #888888,
                                                    stop: 0.8 #aaaaaa,
                                                    stop: 1.0 #ffffff);
                                            color:white;}
                                QPushButton:hover { border:2px solid blue;
                                                    padding:1ex; }
                                QPushButton:pressed { background-color: qlineargradient(
                                                    x0:0, y0:0, x1:1, y1:1, 
                                                    stop: 0.0 #ff1111,
                                                    stop: 0.2 #22ff22,
                                                    stop: 0.4 #4444ff,
                                                    stop: 0.6 #88ee88,
                                                    stop: 0.8 #aaeeaa,
                                                    stop: 1.0 #ffffff); }')
        cppButton.text = 'Changed in JS'
    }
    func()
    

    change-button-js

    3. 运行结果

    result1-link result2-link result3-link

    完整代码见链接

  • 相关阅读:
    用jQuery开发插件详解
    position:absolute和float会隐式的改变display类型
    链家H5项目总结
    jQuery中的选择器
    jqeury实现全选和反选
    $.extend(),与$.fn.extend() 讲解(一)
    mybatis用distinct进行查询的问题
    mybatis 动态Sql的模糊查询
    mysql
    @RequestParam和@PathVariable的区别
  • 原文地址:https://www.cnblogs.com/lgxZJ/p/8158132.html
Copyright © 2011-2022 走看看