【问题标题】:QML component scope puzzleQML 组件范围之谜
【发布时间】:2012-07-05 07:33:19
【问题描述】:

获取此代码:

import QtQuick 1.1

Rectangle {
    width:  100
    height: 100

    property color fromColor: "red"
    property color toColor:   "blue"

    gradient: Gradient {
        property color fromColor: "yellow"
        property color toColor:   "green"

        GradientStop { position: 0; color: fromColor }
        GradientStop { position: 1; color: toColor }
    }
}

为什么Gradient 会从封闭元素中选择其fromColortoColor 属性?

这在哪里记录(至少在源代码 cmets 中,在官方文档中更好)?

注意:这个“QML 混淆示例来自 Girish Ramakrishnan 的演讲 Qt Quick Best Practices and Design Patterns(倒退到第 25 分钟),他确实说事情非常复杂,并且与组件范围有关,但是有没时间解释原因。

[更新]

因此,正如 MartinJ 在下面所说,元素属性(不仅是元素子)层次结构中的顶级组件的属性对所有属性可见,无论嵌套多么深,优先级是该属性的属性,并且根本看不到“中间”项目的所有属性。

这是一个小例子:

import QtQuick 1.1

Item {
    Item {
        property string s: "parent-str"
        Item { Component.onCompleted: console.log(s) }
    }
}

这给出:"ReferenceError: Can't find variable: s"

这按预期工作:

import QtQuick 1.1

Item {
    property string s: "parent-str"
    Item { Component.onCompleted: console.log(s) }
}

,输出"parent-str"

请参阅下方 MartinJ 的 cmets。

【问题讨论】:

  • “如果你有兴趣知道为什么会这样……在谈话结束后随时找我。” (Girish Ramakrishnan 在那次谈话中)。好吧,老鼠。
  • @Slavik81 好吧,仅仅指出这个话题就很有帮助,至少。此外,我们可以随时给他发邮件——如果他没有忘记相关细节的话:)
  • @Slavik81 有点明白了,马丁回答说,我用一个(我希望)澄清的例子更新了我的问题。

标签: scope obfuscation qml


【解决方案1】:

这当然乍一看并不直观,但是在组件根项中注释掉fromColortoColor,原因就很明显了。从QML Scope docs可以看出范围包括:

  • 组件中定义的所有id
  • 本地属性
  • 组件根对象的属性

上例中的GradientStop {} 没有定义本地属性。根组件确实如此,它们是 fromColortoColor 解析到的属性。 Gradient {} 中的属性根本不在GradientStop {} 的范围内。

【讨论】:

  • 好的,我会再考虑一下,不过我想立即问一些问题(因为我已经多次阅读 scoping doc 页面 - 对于 4.7,但似乎从那以后什么都没有改变)。
  • 1.首先,如果在子项中查找名称时忽略父属性(因为 Gradient 是两个 GradienStop 对象的父项),为什么像 Item { property string s: "parent-str"; Item { Component.onCompleted: console.log(s) } } 这样的示例完全有效(这个输出确实输出“paren-str”)?
  • A1.顶级 Item {} 是组件的根,因此它在其所有后代的范围内。
  • A2.将 Gradient 定义移动到一个单独的文件中使其成为一个组件,其中 Gradient 是根,因此在 GradientStops 的范围内。
  • A3。 QML 文件中的顶级项是根。如果您声明一个 Component inline,则该 Component 中的顶级是该组件的根。
【解决方案2】:

另见:

import QtQuick 1.1

Item {
    property string s: "outer"

    Item {
        property string s: "middle"

        property Item it: Item {
            property string dummy: function() { console.log("(5) s: "+s); "" }()
            Component.onCompleted: console.log("(1) s: " + s)
        }

        Item {
            property string dummy: function() { console.log("(4) s: "+s); "" }()

            function f() {
                console.log("(2) s: " + s)
            }

            Component.onCompleted: {
                console.log("(3) s: " + s)
                f()
            }
        }
    }
}

此代码输出:

(5) s: outer
(4) s: outer
(3) s: outer
(2) s: outer
(1) s: outer

请注意,但是(是否针对 Children 属性)以及我们绑定的任何内容(元素或 javascript 代码 sn-p),永远找不到“中间”属性。

因此名称查找是:

  1. 在项目或组件中定义的 ID(参见 3)
  2. 本地属性
  3. 顶级项的属性(或组件,如果它是内联定义的,即使省略了“组件”名称,例如方便地定义委托时)。

另外,当一个属性在组件中被引用,但没有在其中定义时,它仍然可以在“自定义”组件中被引入,并且被看到:

//OverrideInner.qml
import QtQuick 1.1

Item {
    Component.onCompleted: console.log(s)
}

.

//OverrideOuter.qml
import QtQuick 1.1

Item {
    property string s: "overriden-outer"

    Item {
        property string s: "overriden-middle"

        OverrideInner {
            property string s: "overriden-inner"
        }
    }
}

运行“OverrideOuter.qml”会产生:

overriden-inner

再次,请参阅 Martin 的 cmets 和文档以澄清问题。相关文档是:

【讨论】:

    猜你喜欢
    • 2015-06-19
    • 2015-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    相关资源
    最近更新 更多