解析属性和功能“覆盖"在 QML 中
看起来虽然 QML 支持覆盖"属性和函数,但这种支持有点笨拙.这是一个示例片段:
It seems like although QML supports "overriding" of properties and functions, the support is somewhat clunky. Here is an example snippet:
// T1.qml
QtObject {
property int p: 1
function f() { return 1 }
}
// T2.qml
T1 {
property string p: "blah"
function f() { return "blah" }
}
// usage
T1 {
Component.onCompleted: {
var obj = this
for (var k in obj) console.log(k + " " + typeof obj[k] + " " + obj[k])
}
}
T2 {
Component.onCompleted: {
var obj = this
for (var k in obj) console.log(k + " " + typeof obj[k] + " " + obj[k])
}
}
覆盖的行为是一致的——无论一个成员被覆盖多少次,你总是得到正确的,即使你做了这样的事情:
The behavior of overrides is consistent - no matter how many times a member was overridden, you always get the right one, even if you do something like this:
QtObject {
property T1 p : T2 {}
Component.onCompleted: console.log(p.p + " " + p.f())
}
虽然该属性是用 T1 类型声明的,但它引用了一个 T2 对象,因此输出显示为blah blah".
Although the property is declared with type T1, it references a T2 object, and thus the output says "blah blah".
它也适用于每个实例":
It also works on a `per instance" basis:
T2 {
function f() { return 1.5 }
Component.onCompleted: {
console.log(f())
}
}
迭代 T1 的输出如预期:
The output from iterating T1 is as expected:
qml: objectName string
qml: p number 1
qml: objectNameChanged function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }
但是,T2 的输出有点奇怪:
However, the output for T2 is a little odd:
qml: objectName string
qml: p string blah
qml: p string blah
qml: objectNameChanged function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }
它列出了两次覆盖"成员,但是,似乎不是一个来自基本"类型,另一个来自派生" - 因为两个 p
都是字符串.
It lists the "overridden" members twice, however, it doesn't seem like one is from the "base" type and the other from the "derived" - as both p
's are strings.
var obj = this
for (var k in obj) if ((k === "f") && (typeof obj[k] === "function")) console.log(obj[k]())
调用两个 f
函数会输出blah"两次 - 因此同样适用于覆盖"函数.
Calling both f
functions outputs "blah" twice - so the same applies for the function "overrides" as well.
我预计迭代派生"对象会显示属性和函数两次,但其中之一将来自基本类型.让它们实际上是重复的,两者都指代同一个成员似乎毫无意义且不合逻辑.在实例级别覆盖会放置另一个成员,并且再次,所有三个都引用最新的覆盖.因此,从技术上讲,甚至无法手动选择覆盖.
I expected that iterating the "derived" object would show the property and function twice, but one of those would be from the base type. Having them practically duplicated, both referring to the same member seems pointless and illogical. Overriding at instance level puts yet another member, and once again, all three reference the latest override. So it is technically not possible to even pick the overrides manually.
所以我的问题是是否可以指定覆盖:
So my question is whether it is possible to specify the overrides:
// in T2.qml - pseudocode
property string p: T1::p + "blah" // value is "1 blah"
f() { return T1:: f() + "blah" } // returning "1 blah"
尝试以天真的方式去做会导致史诗般的失败:
Attempting to do it in the naive way results in an epic fail:
// in T2.qml
property string p: p + "blah" // binding loop, p does not refer to T1's p
f() { return f() + "blah" } // stack overflow, f does not refer to T1's f
推荐答案
找到一个简单幼稚的手动解决方案:
Found one simple and naive manual solution:
// T1.qml
QtObject {
function f() { return f_t1() }
function f_t1() { return 1 }
}
// T2.qml
T1 {
function f() { return f_t2() }
function f_t2() { return f_t1() + " blah " }
}
// usage
T2 {
function f() { return f_t2() + 1.5}
Component.onCompleted: console.log(f()) // outputs 1 blah 1.5
}
简而言之,为覆盖的继承"的每一级显式命名函数,并使用非修饰函数覆盖进行多态访问,因此现在基"类型的实现可以被派生重用.
In short, have explicitly named function for every level of the "inheritance" that overrides, and use the non-decorated function override for polymorphic access, thus now the "base" type implementations can be reused by the derived.
相关文章