Qt QML中域和符号解析

域和名字解析

QML属性绑定、内联函数、导入的JavaScript脚本都在JavaScript域中执行。域决定了哪些变量一个表达式可以访问以及当出现名字冲突时,哪个变量优先。由于JavaScript的内置域机制非常简单,QML在其基础使其很天然适用于QML语言的扩展。

JavaScript域

QML中的域扩展与JavaScript域是不相冲突的。在QML中编写程序,属性绑定,导入JavaScript,JavaScript程序员可以重用现有知识。

下面的例子中,方法addConstant()将返回传入参数的值加上13作为函数结果,无论QML对象的a和b的属性值是多少。

 QtObject {
      property int a: 3
      property int b: 9

      function addConstant(b) {
          var a = 13;
          return b + a;
      }
  }

QML遵从JavaScript的常规域规则,也使用在属性绑定上。下边的例子将12赋值给QML对象的a属性。

 QtObject {
      property int a

      a: { var a = 12; a; }
  }

每一个JavaScript表达式,函数或者QML中的文件都有其唯一的变量对象。一个变量对象中声明的局部变量绝不会与另外一个变量对象中声明的局部变量有冲突。

类型名和导入的JavaScript文件

QML文档包含了导入声明,声明中定义了类型名称以及该文档可见的JavaScript文件。除了QML自身的声明外,类型名称被JavaScript代码用于访问绑定的属性以及枚举值。

导入的作用应用于每一个属性绑定、QML文档中的JavaScript函数、以及嵌套内联的组件。下面的例子将展示一个简单的QML文件访问枚举变量,调用一个导入的JavaScript函数。

import QtQuick 2.0
import "code.js" as Code

ListView {
      snapMode: ListView.SnapToItem

      delegate: Component {
          Text {
              elide: Text.ElideMiddle
              text: "A really, really long string that will require eliding."
              color: Code.defaultColor()
          }
      }
  }

绑定域对象

一个具有属性绑定的对象被称作是绑定域对象。下面的例子中,Item对象是一个绑定域对象。

Item {
      anchors.left: parent.left
  }

在不使用限定符的情况下,绑定具有访问域对象的权限。上述例子中,在没有给出任何形式的对象前缀的情况下,绑定直接访问了Item的父属性。QML引入了更结构化、面向对象的方法来使用JavaScript,因此不需要使用JavaScript的this属性。

当从绑定中访问附加属性时必须要注意,因为实在与域对象进行交互。概念上来说,即便附加属性只对一部分对象有影响,附加属性在所有对象中都存在。因此未限定的附加属性读取将解析为域对象上的某个附加属性,这常常不是程序员想要的。

For example, the PathView type attaches interpolated value properties to its delegates depending on their position in the path. As PathView only meaningfully attaches these properties to the root object in the delegate, any sub-object that accesses them must explicitly qualify the root object, as shown below.

例如,类型PathView附加了插入值属性到其代理,依赖于其所在位置的路径。由于PathView仅仅在代理中关联该属性到根对象,所有访问它们的子对象必须显式限定根对象。  

PathView {
      delegate: Component {
          Rectangle {
              id: root
              Image {
                  scale: root.PathView.scale
              }
          }
      }
  }

If the Image object omitted the root prefix, it would inadvertently access the unset PathView.scale attached property on itself.

如果Image对象遗漏了root前缀,不经意就会访问其自身的尚未设置的附加属性PathView.scale。

组件域

每一个QML文档中的QML组件都定义了一个逻辑域。每个文档至少有一个根组件,也有其它的内联子组件。组件域是一个组件内所有对象ids和根对象属性的联合体。

Item {
      property string title

      Text {
          id: titletype
          text: "<b>" + title + "</b>"
          font.pixelSize: 22
          anchors.top: parent.top
      }

      Text {
          text: titletype.text
          font.pixelSize: 18
          anchors.bottom: parent.bottom
      }
  }

上面的例子展示了一个简单的QML组件,该组件在顶部显示一个富文本标题,并在底部显示同样的文本。第一个文本类型对象直接访问了该组件的titile属性,用于构建显示文本。根类型的属性是可直接访问的使得在整个组件中分布数据变得简单。

第二个Text类型对象通过一个id直接使用了第一个Text对象的文本。IDs都是QML程序员显式指定的,因此该属性的优先级高于其他属性名称(除了在JavaScript域)。例如,绑定域对象具有一个叫做titletype的属性,titletype作为id仍然具有高优先级。

组件实例层次结构

在QML中,组件实例将组件域连接在一起形成域层次结构。组件实例可以直接访问其祖先组件域。

最容易展示组件域层次结构的例子是内联子组件,内联子组件的组件域隐式地成为外层组件的子域。

Item {
      property color defaultColor: "blue"

      ListView {
          delegate: Component {
              Rectangle {
                  color: defaultColor
              }
          }
      }
  }

组件实例层次结构允许代理组件访问Item类型的defaultColor属性。当然如果该代理组件有一个defaultColor属性,该属性优先级更高。

组件实例域层级结构扩展到跨行的组件。在下面的例子中,TilePage.qml组件创建两个TitleText实例。尽管TitleText类型定义在外部文件中,在TitlePage中依然可以访问title属性。QML是一个动态域语言,依赖于使用的位置,title属性解析结果不同。

 // 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
  }

虽然动态域非常强大,但是必须谨慎使用,以免出现QML代码变得难以预测。一般情况,应该用于两个紧密耦合的组件之间。当构建可重用的组件时,更偏向使用属性接口的方式,如下:

// TitlePage.qml
  import QtQuick 2.0
  Item {
      id: root
      property string title

      TitleText {
          title: root.title
          size: 22
          anchors.top: parent.top
      }

      TitleText {
          title: root.title
          size: 18
          anchors.bottom: parent.bottom
      }
  }

  // TitleText.qml
  import QtQuick 2.0
  Text {
      property string title
      property int size

      text: "<b>" + title + "</b>"
      font.pixelSize: size
  }

重载的属性

QML允许定义在一个对象声明中的属性名称被声明在另一个对象中的属性所重载,如例:

  // Displayable.qml
  import QtQuick 2.0
  Item {
      property string title
      property string detail

      Text {
          text: "<b>" + title + "</b><br>" + detail
      }

      function getTitle() { return title }
      function setTitle(newTitle) { title = newTitle }
  }

  // Person.qml
  import QtQuick 2.0
  Displayable {
      property string title
      property string firstName
      property string lastName

      function fullName()  { return title + " " + firstName + " " + lastName }
  }

在这里,属性名称title在Displayable的头部输出文本,同时也是Person对象中的属性。

根据引用所在的域不同,重载的属性解析结果不同。在Person组件的域中,或者是外部引用Person组件实例的外部域中,title属性引用的结果为Person.qml中的属性。函数fullName中引用的title属性也是声明在Person中的属性。

在Displayable组件中,title属性指向Displayable.qml文件中的属性。函数getTitle和setTitle以及text属性的绑定也都是指向Displayable组件声明的title属性。

尽管共享了相同的名称,两个属性是完全分开的。onChanged信号处理器分别处理各自的属性变化。各自属性的别名也会指向各自。

JavaScript全局对象

QML不允许类型、id以及属性名称与全局对象的属性有冲突,以便出现迷惑。以保证程序执行的结果是满足预期的。详见JavaScript Host Environment了解更多信息。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值