【问题标题】:How to get source code of a QML method in C++?如何在 C++ 中获取 QML 方法的源代码?
【发布时间】:2014-11-08 03:27:05
【问题描述】:

我正在将对象序列化到 QML,并且希望能够获得 QML 对象中定义的函数的源代码。假设我在 QML (test.qml) 中有以下示例:

import QtQml 2.2

QtObject {
    function foo() {
        return 42;
    }
}

我从中创建了一个QObject: obj

有没有什么方法(可以是hacky)在​​不解析QML文件obj创建的情况下获取obj的方法foo的源代码?

可以使用QQmlComponent obj 是从或任何其他Qt 类创建的,只要我不必自己解析即可。或者,如何在不编写我自己的解析器的情况下从test.qml 文件中获取函数的源代码?我不想假设 test.qml 有什么特别之处(例如,它可以与上面的不同,它不必简单到可以使用正则表达式或其他不成熟的 QML 解析器)。

假设它像 JavaScript 一样工作,我尝试了类似的东西:

QQmlExpression expr(engine.rootContext(), obj, "foo.toString()");
QVariant sourceCode = expr.evaluate();

但是,它不起作用。

编辑:根据http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.2,函数对象原型的toString 方法是实现定义的。如果是 QML,我会得到结果:

QVariant(QString, "function() { [code] }")

由于似乎没有办法通过 JS 或 C++ 获取代码,因此我不再将自己局限于公共 Qt API。

【问题讨论】:

  • 您想要源代码?还是只想运行函数?
  • 我需要源代码,而不是运行函数。

标签: javascript c++ qt qml qt5


【解决方案1】:

我认为从已经创建的 QML 对象中获取函数的源代码是不可能的。它似乎没有任何 C++ 接口,JavaScript 也没有使用 toSource 方法返回它。

但是,可以使用 QML 解析器来检索它。坏消息是 QML 解析器是 Qt 私有 API 的一部分,因此在使用不同的 Qt 库构建时它可能无法正常工作。

使用 Qt 5.3.0 私有 API 解析 QML 的代码或多或少:

.pro文件:

QT += qml qml-private

cpp文件:

using namespace QQmlJS::AST;

class LVisitor: public QQmlJS::AST::Visitor {
public:
    LVisitor(QString code): _code(code) {}

    virtual bool visit(FunctionBody *fb) {
        qDebug() << "Visiting FunctionBody" <<
                    printable(fb->firstSourceLocation(), fb->lastSourceLocation());
        return true;
    }

private:
    QStringRef printable(const SourceLocation &start, const SourceLocation &end) {
        return QStringRef(&_code, start.offset, end.offset + end.length - start.offset);
    }

private:
    QString _code;
};

void testQmlParser() {
    QFile file(":/test.qml");
    file.open(QFile::ReadOnly);
    QString code = file.readAll();
    file.close();

    QQmlJS::Engine engine;
    QQmlJS::Lexer lexer(&engine);

    lexer.setCode(code, 1, true);

    QQmlJS::Parser parser(&engine);

    if (!parser.parse() || !parser.diagnosticMessages().isEmpty()) {
        foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
            qDebug() << "Parse" << (m.isWarning() ? "warning" : "error") << m.message;
        }
    }

    UiProgram *ast = parser.ast();

    LVisitor visitor(code);
    ast->accept(&visitor);
}

要获取有关定义函数的对象的更精确信息或只是从 AST 获取更多信息,请实现更多 QQmlJS::AST::Visitor 方法。

【讨论】:

    【解决方案2】:

    我也没有找到任何方法。但我找到了解决办法。

    reffer this 优先

    现在,如您所知,我们可以在 C++ 中访问 QML 对象。将执行以下操作以在 QML 中运行该函数。

    Item {
        width: 100; height: 100
    
        Rectangle {
            property bool call:true
    
            objectName: "rect"
            onCallChanged()
            {
                 myFunction();
            }
            function myFunction()
            {
                 //your code
            }
        }
    }
    

    在 C++ 中,您必须执行以下操作:

    QObject *rect = object->findChild<QObject*>("rect");
    if (rect)
        rect->setProperty("call", !(rect->property("call").toBool()));
    

    这里我们使用属性'call'的更改事件来调用myFunction()

    【讨论】:

    • 我需要源代码,而不是运行函数的方法。此外,要运行我提供的 sn-p 功能就可以了:QQmlExpression expr(engine.rootContext(), obj, "foo()");.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-28
    • 2015-07-02
    • 2011-12-27
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多