Effective QML Part0:编码规范

Item 0:编码规范


本节提供有关如何格式化属性,信号和函数的顺序,以使事情变得轻松并快速切换到相关代码块。

QML对象属性始终按以下顺序构造:

  • id
  • 属性声明
  • 信号声明
  • 对象声明
  • 状态(States)
  • 变换(Transitions)
  • 信号处理器(Signal handlers)
  • 子对象
    • 可视对象
    • Qt提供的不可见对象
    • 自定义的不可见对象
  • QtObject所包装的私有数据
  • JavaScript函数
Rectangle {
    id: photo

    property bool thumbnail: false // 属性声明
    property alias image: photoImage.source

    signal clicked // 信号声明

    x: 20
    y: 20
    height: 150
    color: "gray" //对象声明
    width: { // 较大的绑定
        if (photoImage.width > 200) {
            photoImage.width;
        }
        else {
            200;
        }
    }
    states: State { // 状态
        name: "selected"
        PropertyChanges { target: border; color: "red" }
    }
    transitions: Transition { // 变换
        from: ""; to: "selected"
        ColorAnimation { target: border; duration: 200 }
    }
    onSomeEvent: {

    }

    Rectangle { // 子对象 - 可视对象
        id: border
        anchors.centerIn: parent; color: "white"

        Image { id: photoImage; anchors.centerIn: parent }
    }

    Timer { } // 子对象 - Qt提供的不可见对象

    MyCppObject { } // 子对象 - 自定义的不可见对象

    QtObject {
        id: privates

        property var privateProperty: null

    }

    function doSomething(x) { // JavaScript 函数
        return x + photoImage.width
    }
}

信号处理顺序


当处理在Item上的信号时,要始终记得将Component.onCompleted放在最后一行.

// 错误的示例
Item {
    Component.onCompleted: {
    }
    onSomeEvent: {
    }
}

// Correct
Item {
    onSomeEvent: {
    }
    Component.onCompleted: {
    }
}

放在末尾是为了更好的符合心里预期:在组件构造结束时会触发Component.onCompleted。


如果一个Item中有多个信号处理程序,则将行数最少的那些处理程序放在顶部。 随着实现线的增加,处理程序也向下移动。 唯一的例外是Component.onCompleted信号,它始终放在底部。

// 错误示例
Item {
    onOtherEvent: {
        // Line 1
        // Line 2
        // Line 3
        // Line 4
	}
    onSomeEvent: {
        // Line 1
        // Line 2
    }
}

// 正确示例
Item {
    onSomeEvent: {
        // Line 1
        // Line 2
    }
    onOtherEvent: {
        // Line 1
        // Line 2
        // Line 3
        // Line 4
    }
}

属性的顺序


第一个赋值的属性必须是id。 如果要声明组件的自定义属性,则声明始终位于第一个属性赋值的上方。

// 错误示例
Item {
    someProperty: false
    property int otherProperty: -1
    id: myItem
}

// 正确示例
Item {
    id: myItem

    property int otherProperty: -1

    someProperty: false
}

属性赋值还有一些预定义的顺序。 顺序如下:

  • id
  • x
  • y
  • width
  • height
  • anchors

这里的目标是将最明显和定义最明确的属性放在顶部,以方便访问和查看。 例如,对于图像,我们可能决定将sourceSize也放置在anchors上方。


如果同时还有属性赋值和信号处理器,请确保始终将属性赋值放在信号处理程序上方。

// 错误示例
Item {
    onOtherEvent: {
    }
    someProperty: true
    onSomeEvent: {
    }
    x: 23
    y: 32
}

// 正确示例
Item {
    x: 23
    y: 32
    someProperty: true
    onOtherEvent: {
    }
    onSomeEvent: {
    }
}

如果将属性赋值与信号处理器混合在一起,通常很难看到它们。 这就是为什么我们将分配放在信号处理程序之上。

函数顺序


尽管QML中没有私有和公共函数,但是我们可以通过使用QtObject进行包装还达成类似的效果

公共函数实现始终放在文件的最底部。

// 错误示例
Item {

    function someFunction() {
    }

    someProperty: true
}

// Correct
Item {
    someProperty: true
    onOtherEvent: {
    }
    onSomeEvent: {
    }

    function someFunction() {
    }
}

动画


当使用Animation的任何子类时,尤其是嵌套的子类(如SequentialAnimation)时,请尝试减少一行中的属性数量。 一段时间后,很难推理出同一行中的2-3个以上的赋值。

由于在我们的脑海中很难想象动画,因此我们将受益于使动画尽可能简单,因为它们每帧执行一次。 尝试给他们提供有意义的ID或对象名称,以帮助我们将来在出现问题时对动画进行自我调试。

// 坏的例子
NumberAnimation { target: root; property: "opacity"; duration: root.animationDuration; from: 0; to: 1 }

// Depends on your convention. The line does not exceed 80 characters.
PropertyAction { target: root; property: "visible"; value: true }

// 好的例子
SequentialAnimation {
    PropertyAction {
    	target: root
    	property: "visible"
    	value: true
    }

    NumberAnimation {
    	target: root
        property: "opacity"
        duration: root.animationDuration
        from: 0
        to: 1
    }
}

可以放弃部分组件的id


如果一个组件不需要被如何访问,请避免设置id属性。 这样,我们就不会混淆命名空间中的id,或者更可能的产生明明冲突.

最好使用id最多3-4个字符的缩写,以便在查找某个组件(例如TextBox)时,只需键入tb即可列出所有文本框的ID。

命名规则为[组件名缩写] [组件具体描述],例如tbEmail,btnLogIn

TextBox {
    id: tbEmail
}

Button {
    id: btnSubmit
}

CheckBox {
    id: cbAgreement
}

确保最外层的组件使用root作为id

属性赋值


分配分组的属性时,如果只更改一个属性,则始终首选点号。 否则,请始终使用组符号。

Image {
    anchors.left: parent.left // 通过. 来访问
    sourceSize { // 通过组符号来访问
        width: 32
        height: 32
    }
}

在同一文件中的不同位置将组件分配给Loader的sourceComponent时,请考虑使用相同的实现。 例如,在以下示例中,存在同一组件的两个实例。 如果两个SomeSpecialComponent都是相同的,则最好将SomeSpecialComponent包装在Component中。

// BEGIN 坏的示例.
Loader {
    id: loaderOne
    sourceComponent: SomeSpecialComponent {
        text: "Some Component"
    }
}

Loader {
    id: loaderTwo
    sourceComponent: SomeSpecialComponent {
        text: "Some Component"
    }
}
// END 坏的示例.

// BEGIN 好的示例.
Loader {
    id: loaderOne
    sourceComponent: specialComponent
}

Loader {
    id: loaderTwo
    sourceComponent: specialComponent
}

Component {
    id: specialComponent

    SomeSpecialComponent {
        text: "Some Component"
    }
}
// END 好的示例.

这样可以确保无论何时对specialComponent进行更改,它都将在所有装载程序中生效。 在坏的的示例中,我们将必须重复相同的更改。

Import语句


Import在QML中花费时间。而且,如果我们正在开发系统规格较低的设备,那么我们将需要尽可能地优化。在这种情况下,请尝试最小化我们在QML文件中使用的导入次数。

如果还需要导入JavaScript文件,请确保在QML文件和JavaScript文件中都不包含相同的模块。 JavaScript文件共享从QML文件导入的内容,因此我们可以使用用它。

如果不使用QML中导入的modules,请考虑将import语句移至JavaScript文件。但是请注意,一旦在JavaScript文件中导入了某些内容,导入内容将不再共享。有关完整规则,请参见此处

另外,我们还可以使用Qt.include()复制包含文件的内容,而不必担心导入共享规则。

导入顺序
导入其他模块时,请按照以下顺序进行:

  • Qt模块
  • 第三方模块
  • 本地C ++模块导入
  • QML文件夹导入
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章