当我们要显示包含变量的文字时,在 Qml 里面怎么实现?下面我们就提供一种方法。
功能需求
可配置的文字能够满足很多需求,如果我们能够让可配置的文字中包含变量,并且支持动态的计算,那就让程序的迭代变得更加灵活了。
比如在出错提示场景,我们考虑将出错时,程序的一些相关状态一同展示出来。
Failed to move object ${canvas.movingObject}, it's now position at (${canvas.movingObject.x}, ${canvas.movingObject.y}).
这段文字可能来源于一个错误码描述文件,也可能来源于服务后台配置的文字。
随着使用迭代,错误文字得到了逐步完善,甚至里面的变量也会新增或者替换成其他的。
与 Qt 语言翻译配合,我们可以只更新翻译(.qm)文件,就可以不用修改代码、升级应用。
Qt 语言翻译提供基于字符串 format 的变量文字方案,但是需要预埋固定数量的参数,并且需要代码配置,没有本文的方案灵活。
实现方案
如果直接通过 Qml 代码实现,上面的字符串,可能会这样写:
Text {
text: "Failed to move object " + canvas.movingObject +
", it's now position at (" + canvas.movingObject.x + ", " + canvas.movingObject.y + ")."
}
显然这代码写出来就固定了,不能灵活的修改。但是如果我们动态生成这段代码呢?那我告诉你,在 Qml 中,这是可行的。
你可能会先想到 eval,通过 Qt.eval 方法,可以执行动态的代码,显然计算出一个字符串不在话下。但是假如上面的文字在显示的时候,对象还在不停移动,其 x、y 还在变化,要跟踪其变化,通过 eval 就不太好做了。
我们的方案是这样的:
首先,动态生成一个 Qml 对象,就像上面的 Text 那样,其有一个属性是这个动态计算的字符串。
然后,将目标属性与该对象的这个字符串属性绑定,这样就能跟踪 x、y 这些变量的变化了。
最后,我们还要记得及时释放动态创建的对象,以免引起内存泄露。
DynamicString.qml
QtObject {
property string input
property string output
property var object
onInputChanged: {
var lastObject = object
var script = File.content("qrc:/DynamicString.qml")
script = script.replace("output", "output: " + input.replace(/\$\{([\w()\.]+)\}/g, "\"+($1)+\""))
object = Qt.createQmlObject(script, this, "DynamicString.qml")
output = Qt.binding(function() { return object.output })
if (lastObject) lastObject.destroy()
}
}
Test.qml
DynamicString {
id: errorDynamicString
property var canvas: parent // The variable used by error strings
input: errorString
}
Text {
text: errorDynamicString.output
}