1
对于一个组件(一个.qml文件),根对象的属性可以被外部访问,但是子对象的属性对外是不可见的,即
[父对象id].[子对象id].[子对象属性]
的写法是不允许的,如
//MyItem.qml
import QtQuick 2.12
Item{
id:rootItem //根对象id
property string name:"hello"
Item{
id:childItem //子对象id
property string name:"world"
}
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id:root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem{
id:myItem
Component.onCompleted:{
myItem.name = "haha"; //正确
myItem.childItem.name = "heyhey"; //错误
}
}
}
上述代码运行报错:
TypeError: Value is undefined and could not be converted to an object
如果外部想访问(读、写)一个组件内的子对象属性,应该使用属性别名,如
//MyItem.qml
import QtQuick 2.12
Item{
id:rootItem //根对象id
property string name:"hello"
property alias childName:childItem.name //属性别名的写法
Item{
id:childItem //子对象id
property string name:"world"
}
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id:root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem{
id:myItem
Component.onCompleted:{
myItem.name = "haha";
myItem.childName = "heyhey"; //修改myItem内的childItem.name
}
}
}
或者整个item作为属性别名导出
//MyItem.qml
import QtQuick 2.12
Item{
id:rootItem //根对象id
property string name:"hello"
property alias item:childItem //属性别名的写法
Item{
id:childItem //子对象id
property string name:"world"
}
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id:root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem{
id:myItem
Component.onCompleted:{
myItem.name = "haha";
myItem.item.name = "heyhey"; //直接访问myItem.childItem
}
}
}
属性别名不会分配内存,其相当于目标属性的引用
其实,只要是作为属性的对象(不管是属性别名,还是一般的属性),就可以直接访问,即
[父对象id].[子对象属性名].[子对象属性]
2
以下考虑跟上述相反的情况,一个组件则可以访问外部组件的属性,因为组件在其声明(创建了对象实例)的时候,就属于所在的作用域,因此可以访问这个作用域内的对象及属性,如
// TitlePage.qml
import QtQuick 2.0
Item {
property string title
TitleText {
size: 22
anchors.top: parent.top
}
TitleText {
size: 18
anchors.bottom: parent.bottom
}
}
// TitleText.qml
import QtQuick 2.0
Text {
property int size
text: "<b>" + title + "</b>"
font.pixelSize: size
}
上述的TitleText内用到了title属性,我们知道Text是没有这个属性的,它会自动到上一层去寻找这个属性。
这一点就很危险了,如果我们粗心使用了未定义的属性,程序可能不会报错,因为这个属性可能存在于上一层对象的作用域中,当然qt官方也不建议这种用法:Scope and Naming Resolution
3
同一个qml内,任意对象属性均可以相互访问,通过[对象id].[属性]的形式访问,如果不写对象id,那么将会首先在当前对象内寻找这个属性,所以要注意漏写对象id导致修改了错误的属性,如
//MyItem.qml
import QtQuick 2.12
Item{
id:rootItem //根对象id
property string name:"hello"
Item{
id:branch0 //对象分支0
anchors.fill: parent
property string name:"world"
Rectangle{
id:child0 //子对象的子对象
property string name:"!!!"
anchors.fill: parent
MouseArea{
id:mousearea
anchors.fill: parent
onClicked: {
name = branch1.name //这里原想修改child0.name,但最终修改的是rootItem.name,因为onClicked是mousearea的事件,而mousearea中没有定义name,就到MyItem.qml的组件作用域中寻找了
console.log("[2]")
console.log("rootItem.name="+rootItem.name)
console.log("branch0.name="+branch0.name)
console.log("child0.name="+child0.name)
console.log("branch1.name="+branch1.name)
console.log("child1.name="+child1.name)
}
}
Component.onCompleted: {
name=child1.name //这里修改的就是child0.name,因为Component.onCompleted是child0的附加属性事件,属于child0的作用域
console.log("[1]")
console.log("rootItem.name="+rootItem.name)
console.log("branch0.name="+branch0.name)
console.log("child0.name="+child0.name)
console.log("branch1.name="+branch1.name)
console.log("child1.name="+child1.name)
}
}
}
Item{
id:branch1 //对象分支1
anchors.left: branch0.right
property string name:"dog"
Rectangle{
id:child1 //子对象的子对象
property string name:"???"
}
}
Component.onCompleted: {
console.log("[0]")
console.log("rootItem.name="+rootItem.name)
console.log("branch0.name="+branch0.name)
console.log("child0.name="+child0.name)
console.log("branch1.name="+branch1.name)
console.log("child1.name="+child1.name)
}
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem{
id:item
anchors.fill: parent
}
}
鼠标点击后,打印:
qml: [0]
qml: rootItem.name=hello
qml: branch0.name=world
qml: child0.name=!!!
qml: branch1.name=dog
qml: child1.name=???
qml: [1]
qml: branch0.name=world
qml: child0.name=???
qml: branch1.name=dog
qml: child1.name=???
qml: [2]
qml: rootItem.name=dog
qml: branch0.name=world
qml: child0.name=???
qml: branch1.name=dog
qml: child1.name=???
刚才说了,直接写[属性],会首先在当前对象作用域内寻找属性,那如果当前对象没有这个属性呢?排除第2节提到的情况,这里要分三种情况讨论:
(1)在当前对象中存在属性时,此时直接写[属性]是没问题的。
(2)如果当前对象作用域内没有属性,而根对象作用域定义了属性,此时直接写[属性]的隐藏的id将会是根对象id,说明属性的访问规则是优先当前作用域,再者是根对象作用域
//MyItem.qml
import QtQuick 2.12
Item{
//[0] rootItem作用域
id:rootItem //根对象id
property string name:"hello"
property int age:10
function printName()
{
childItem1.printName()
childItem2.printName()
}
function printAge()
{
childItem3.printAge();
}
Item{
//[1] childItem1作用域
id:childItem1 //子对象id
property string name: name+" world" //注意,这里的name就是childItem1.name!此处会导致循环绑定,QML Item: Binding loop detected for property "name"
function printName()
{
console.log(name);
}
//[1] childItem1作用域
}
Item{
//[2] childItem2作用域
id:childItem2 //子对象id
property int age:20
property string name1: name+" world" //这里的name就是rootItem.name
function printName()
{
console.log(name1);
}
Item{
//[3] childItem3作用域
id:childItem3
function printAge()
{
console.log(age) //打印结果:“10”,这里的age为rootItem.age,并不是childItem2.age
}
//[3] childItem3作用域
}
//[2] childItem2作用域
}
//[0] rootItem作用域
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem {
id:item
}
Component.onCompleted: {
item.printName()
item.printAge()
}
}
(3)如果根对象作用域、当前对象作用域内均没有属性,此时直接写[属性]则会报错not defined,如
import QtQuick 2.12
Item{
//[0] rootItem作用域
id:rootItem //根对象id
property string name:"hello"
//property int age:10 //此处注释掉
function printName()
{
childItem1.printName()
childItem2.printName()
}
function printAge()
{
childItem3.printAge();
}
Item{
//[1] childItem1作用域
id:childItem1 //子对象id
property string name: rootItem.name+" world"
function printName()
{
console.log(name);
}
//[1] childItem1作用域
}
Item{
//[2] childItem2作用域
id:childItem2 //子对象id
property int age:20
property string name1: name+" world" //这里的name就是rootItem.name
function printName()
{
console.log(name1);
}
Item{
//[3] childItem3作用域
id:childItem3
function printAge()
{
console.log(age) //错误,ReferenceError: age is not defined,并不会到childItem2的作用域里寻找age
}
//[3] childItem3作用域
}
//[2] childItem2作用域
}
//[0] rootItem作用域
}
可见,不注意对象作用域将埋下许多地雷,最好是养成习惯,不管在哪里,属性前面都加上对象的id