原文 QML Engine Internals, Part 4: Custom Parsers
———————————————————————————————————————————
简要回顾
Q_PROPERTYs无处不在?
让我们稍微扩展一下这个例子,当鼠标点击时,将矩形变红:
自定义解析器
仔细阅读QQuickPropertyChanges类的头文件,我们找到了一点破解颜色属性秘密的线索:在文件末尾还有另一个类:QQuickPropertyChangesParser,它继承于QQmlCustomParser。
想要了解自定义解析器到底是如何工作的,我们得先回顾一下QML文件的加载,在第一篇博文中就已经讲解了,QML文件的加载分为两个阶段:
1.编译阶段
QML文件会被解析和编译一次,最后会创建一个包含指令列表的QQmlCompiledData对象。除指令列表外,它还包含了一些补充这些指令的二进制数据。阅读之前的博文可以看到这些指令是什么样子的。
2.生成阶段
当QML文件被实例化后,QML引擎就会在QQmlCompiledData对象中查找指令,并在虚拟机中执行它们。
自定义解析器在编译和生成阶段都会被调用:
1.在编译阶段,QQmlCustomParser::compile()将被调用
下面的一点调试代码证实了颜色属性是被传递到了自定义解析器中:
输出:
就PropertyChanges的自定义解析器而言,它只是简单地将参数按原样序列化存入QByteArray。
2.在生成阶段,QQuickPropertyChangesParser::setCustomData()将被调用
在我们这个例子中,PropertyChanges的自定义解析器只是简单地把数据传递给QQuickPropertyChanges对象。稍后,由QQuickPropertyChangesPrivate::decode()对这些数据做一些处理:对数据进行反序列化。然后创建一个ExpressionChange对象列表。当属性改变时,这些ExpressionChange就会被执行。
因为QQmlCustomParser是私有的API,所以编写自己的自定义解析器并不是那么简单。
总结
为了支持QML元素中的任意属性,除了使用正常的Q_PROPERTYs,还需要使用自定义解析器。这些自定义解析器获得所有未知属性的列表后,可以对这些属性做任何处理。QML文件的加载过程中,存在编译和生成两个阶段。在编译阶段,自定义解析器创建一个存储二进制数据QByteArray,它存储所有在生成阶段需要的信息。在生成阶段,这个QByteArray被传递给了自定义解析器,这时自定义解析器才真正意义上地使用这些数据。
讨论
PropertyChanges元素具有自定义分析器是相当方便的,仅列出color: "red"就相当不错了。更妙的是,你可以很轻松地列出多个属性:
与之形成对比的是,使用稍微丑陋一点语法的PropertyAction:
这里存在一个不一致的地方:在一种情况下,能够使用优美的语法,在其他情况下,则不能。在我看来是相当混乱的,特别是在你不了解自定义解析器的情况下。
另一个例子是ListElement元素,它同样具有一个自定义解析器。因为它的属性是由自定义解析器解析的,它们表现得不太像正常属性。就我个人而言,我偶然发现了它们的奇怪行为,比如QTBUG-16289。
最后一个使用自定义解析器的例子是Connections元素,当连接到一个从C++里导出的对象的信号时,这是非常有用的:
你是怎么看待自定义解析器存在的意义的?
至此,4篇文章全部翻译结束了,如果有什么疑问或者对QML应用和研究感兴趣的朋友,欢迎加入我们进行讨论(QQ群:280689979)。如需转载,无须我们授权,但需要注明原文链接(该文的链接),及原作者,谢谢!