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文件夾導入
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章