qml編碼規範與指導

qml編碼規範與指導

說明

良好的編程規範能夠大幅提升一個程序的可讀性、可維護性。編碼規範是你們達成一致的約定,這樣你們的代碼就能夠互相看懂,維護起來更容易,思想更暢快的交流,經驗更快的獲得傳播。javascript

QML是一種聲明方式設計的語言,用來設計應用程序的界面,包括式樣和表現行爲。在QML中,一個用戶界面被制定爲一棵樹形的對象模型而且包含了對象的屬性,這棵樹樹根對應的就是qml文件中的根組件。
JavaScript在QML中做爲一種腳本語言,對QML進行邏輯方面的編程,也能夠說QML是對JavaScript的擴展,提供了js主機環境。
QML中的JavaScript是特殊的JavaScript,是簡化的JavaScript。java

Item {
    id:root
    width:800
    height:480
    Rectangle {
        x:200
        y: 60
        width:200
        height:160
        color:「red」
        visible: false
    }
}

Rectangle組件中一些語法的聲明能夠寫成JavaScript的方式:c++

Item {
    id:root
    width:800
    height:480
    property bool visibleState: false
    property bool lightState: false
    Rectangle {
        x: parent.widht/4
        y: parent.height/8
        width:parent.widht/4
        height:parent.height/3
        color:root.lightState ? 「red」 : "green"
        visible: root.visibleState ? true : false
    }
}

經過以上兩段QML代碼中Rectangle組件屬性的賦值狀況能夠看出,組件的屬性能夠直接賦值,也可經過JavaScript代碼賦值。git

指導性原則

統一的代碼風格,減小代碼冗餘,加強其代碼可讀性,還能夠提高工做效率,讓程序更清晰、健壯。編程

詳細說明

文件命名

這裏的文件分爲 _*.qml_ 文件和 _*.js_ 文件。框架

qml文件命名

因每個qml文件的使用方法可能不固定,在某些狀況下做爲程序的入口文件,文件名的首字母能夠大寫,也能夠小寫,但在另外一些狀況下可能做爲Component(控件,類)來使用,首字母必須大寫。例如:
mainScreen.qml是一個程序界面的入口文件,在後續的維護中,須要在mainScreen.qml中添加一系列的按鈕,在這種狀況下,能夠從新寫一個繼承於mainScreen的界面入口文件main.qml,此時則需從新命名mainScreen.qml爲MainScreen.qml。
爲了方便qml文件的維護,避免上述狀況的發生,qml文件的命名規則爲:函數

  • 僅由英文字母組成。
  • 以大寫字母開始,遵循大駝峯的命名規則,例如:佈局

    SwithcButton.qml
    ListButton.qml
    MainScreen.qml

js文件命名

  • js文件名由小寫的英文字母和_組成。
  • js文件名一概以「 impl 」結尾。
    例如:datetime_helper_impl.js
    這樣便於在qml中導入
    *.js_ 文件時,方便命名別名。

編寫qml文件

import

import的意思是導入模塊,相似java語言中的import包,用來導入qml文件所要用到的內置模塊、自定義插件、控件、js文件等。
qml文件中,import模塊的順序爲:動畫

  1. 導入 Qt 內置模塊
  2. 導入框架自定義 Qt Quick 模塊
  3. 導入項目自定義 Qt Quick 模塊
  4. 導入本地 _*.qml_ 組件包
  5. javascript 導入腳本文件
  6. javascript 引用腳本模塊

例如:ui

// ModuleA.qml

import QtQuick 2.6
import QtQuick.Controls 2.1

import net.phoneyou.EasyUI 1.0 as HUI
import net.phoneyou.EasyUI.Material 1.0 as HUIMaterial
import net.phoneyou.Roshan.MapRender 1.0 as MapRender2D

import your_project_name 1.0
import "path_to_package"

import "my_component_impl.js" as MyComponent
.import "utils.js" as Utils

爲了不不一樣模塊之間的命名衝突,咱們在導入模塊時可使用「as」關鍵字設置該模塊在本 qml 文件中的「別名」。

對於"as"的相關規則說明:

  • 導入Qt內置模塊的版本號爲對應的Qt版本的最高版本號。
  • js文件導入到qml中必需要有別名。
  • 在導入模塊中,自己就有命名衝突時,需給其中至少一個模塊都設置別名
  • 不對 Qt 內置模塊設置別名
  • 對於自定義模塊需設置別名
  • 別名做爲模塊在所屬 qml 文件中的代號,需保持文件內的惟一性
  • 別名的命名規則採用「大駝峯」

爲了保證 Qt 內部組件和命名空間不被污染以及保持代碼能夠順利升級--好比升級 Qt 版本,須要確保不對 Qt 模塊設置別名,而對其餘,好比HUI、Roshan以及其餘三方的或者項目內的模塊,進行「別名」處理。尤爲是那些對常見控件進行定製的模塊。

根組件

qml文件描述的實際上一個由 「UI組件節點」 組成的「樹」。而「根組件」也就是「根節點」,在qml文件有且只有一個。

根組件做爲邏輯上的頂層組件,直接承擔起了 qml 文件的全部定義,其屬性、信號、方法即爲該 qml 組件的屬性、信號、方法。

其餘組件只能做爲其子節點存在,對外是不可見的,相似 private 做用域,他們的屬性、信號、方法命名需添加雙下劃線("__")前綴,而根組件沒有任何的先後綴。

關於根組件的類型:

  • 若是該qml文件聲明的是對已有組件進行改造的可複用的組件,好比 「ImageButton」,那麼該根組件應該爲「Button」或者其餘的什麼「Button」,對應的別名應該設置爲「button」或「root」。
  • 若是該qml文件聲明的是一個複合的功能型界面,好比說「ReplaybackPanel」,「DataDelegateItem」,它是一系列組件的組合,通常將根組件設定爲「Item」或者「Rectange」,其別名應設置爲「root」。

根組件定義

  1. id
  2. 自定義屬性property
  3. 信號signal
  4. JavaScript function
  5. 自帶屬性設置object properties
  6. 子控件child objects
  7. 狀態states
  8. 動畫animation、漸變transitions

例如:

Rectangle {
      id: root
      /*! 鼠標按下狀態,當鼠標按下時爲true */
      property bool pressed: false

      /*! 圖片資源 */
      property alias source: photoImage.source

      /*! 鼠標點擊事件 */
      signal clicked

      /*! 返回photoImage的width */
      function doSomething()
      {
          return photoImage.width
      }

      width: {
          if (photoImage.width > 200) {
              photoImage.width;
          } else {
              200;
          }
      }
      height: 480
      color: "gray"

      Rectangle {
           id: photoRect
           x: 20
           y: 20
           width: parent.width
           height: 200
           color: "white"
           Image {
               id: photoImage
               anchors.centerIn: parent
            }
      }
      MouseArea {
          anchors.fill: parent
          onPressed: {
              root.pressed = true
          }
          onClicked: {
              root.clicked()
          }
      }
      states: State {
          name: "selected"
          when: root.pressed
          PropertyChanges {
              target: root.border
               color: "red"
          }
      }

      transitions: Transition {
          from: ""
          to: "selected"
          ColorAnimation {
              target: root.border
              duration: 200
          }
      }
  }
id

在聲明組件時,能夠同時聲明其「id」屬性。「id」屬性是該組件的代號,聲明該屬性的好處是,能夠被它的做用域爲:。

同一qml文件中,每一個控件均可以設置id屬性,且不能相同,id相同會有書寫錯誤提示。

具體命名規則以下:

  • 由字母組成,首字母必須小寫,以小駝峯的形式命名。
  • 以控件類型結尾,例如:
    將Button的id設置爲:xxxxBtn 或 xxxxButton
    將Text的id設置爲: xxxxTxt 或 xxxxText
    將ComboBox的id設置爲: xxxxCmb 或 xxxxComboBox
    這樣根據id就能夠知道其對應的是什麼控件。
    只有在明確知道其控件的縮寫時,才能在id中使用縮小,不然一概使用控件全稱。
    部分控件的縮寫詳見「經常使用控件的縮寫」
  • 控件默認不設置id屬性,若某個控件的id須要被使用(控件間存在關聯關係),纔要設置id。
    例如控件的佈局存在相對位置的關係或控件間的屬性在邏輯上存在依賴關係等,則須要設置id,例如:

    Item{
          width: 200
          height: 300
          Button{
              id: saveBtn
              width: 60
              height: 30
              text: "Save"
          }
          Button{
              anchors {
                  top: saveBtn.bottom
                  topMargin: 10
                  left: saveBtn.left
              }
              width: 60
              height: 30
              visible: saveBtn.visible
          }
      }
    代碼中的Item和第二個Button沒有被引用到,沒必要設置id,這樣可避免設置過多的無用id,徒增命名的煩惱。
  • 當子控件要使用父控件的屬性或根據父控件設置相對位置時,不要使用父控件的id,用parent代替id。例如:

Item {
    id: root
    width: 800
    height: 480
    Rectangle{
        id: testRect
        anchors.centerIn: parent
        width: parent.width/2
        height: 200
        color: "red"

        Button{
            id: testBtn
            width: parent.width/2
            height: 40
            text: "1233"
            highlighted: (parent.color === "red") ? false : true
        }

    }
}
  • 一個qml文件中,設置id的個數不要超過7個,多餘7個,則要進行qml代碼的拆分,建議設置3到4個。
  • 同一個qml文件中的控件id在文件中是通用的,可是delegate中的控件id除外,delegate中控件id只在delegate中有效,外部訪問無效。
    由於 delegate爲Component類型,外界沒法訪問。
    通俗點講,就是delegate通常用來承載model數據的顯示,一個id對於多個數據顯示控件,外部在使用id時,沒法定位當前使用是哪一個數據控件的id。例如:
ListView {
        id:listView
        anchors.centerIn: parent
        width: 160
        height: 240

        model: Qt.fontFamilies()

        delegate: ItemDelegate {
            id:fontDelegate
            text: modelData
            width: parent.width
            highlighted: ListView.isCurrentItem
            onClicked:{
                listView.currentIndex = index
                console.log("clicked:", modelData)
            }
        }
    }

代碼中ItemDelegate的id名稱fontDelegate,是不能在ItemDelegate以外被使用的。

property屬性

在qml代碼中,爲了方便外界使用本自定義控件或者便於qml文件內部控件之間的關聯,常須要自定義一些屬性。
一個property是對象的一個屬性,能夠被賦爲靜態值或者是綁定到動態表達式上。一個property的值能夠被其它的對象讀取。通常狀況下,property屬性也能夠被其它對象修改,除非該QML類型明確指定該property屬性不能被修改。

  • 屬性的命名規則:
    屬性名稱必須是以小寫字母開頭,僅由字母、數字和下劃線組成,由 名詞或形容詞+名詞 的小駝峯形式組合而成。
    當定義的屬性僅限qml內部使用時,纔會用到_,這樣的私有屬性的命名必須以兩個下劃線(__)開始,例如:
property var __locale: Qt.locale()
自定義屬性

自定義屬性的語法格式以下:

property <propertyType> <propertyName> : value
  • 定義一個自定義的property屬性也就爲該property屬性隱式的建立了一個value-change信號,也就是關聯了一個名爲 on Changed的signal handler。 就是property屬性的名稱,並且首字母要大寫。,以下所示:
Rectangle {
        property string someText: 「 」
        onSomeTextChanged: console.log("The someText will be: " + someText)
    }
  • 自定義的屬性必須要有初始值,除了Object Types
  • 常見自定義的屬性類型:
    bool,double,int,real,string,url,var,list
  • bool:true/false。
  • double:雙精度實數,有小數點。
  • int:整數,能夠是負數、0、正數。
  • real:實數,有小數點。
  • string:字符串。
  • url:資源路徑,能夠是絕對路徑或相對路徑,相對路徑時就會被轉換爲URL對象,若是使用了Qt資源系統,就要用「qrc:///」代替「:/」。
  • var:基本類型是通用的類型,能夠保存任意類型的值,包括lists和objects:
    任何標準的JavaScript類型均可以使用通用的var類型建立和存儲。
    若是聲明一個屬性用於存儲列表值,但不必定是存儲QML對象類型值,這個時候你就須要聲明var的property屬性。
property var someNumber: 1.5
    property var someString: "aaa"
    property var someBool: true
    property var someList: [2,5,"one","two"]
    property var someObject: Rectangle {
                                width: 100
                                height: 100
                                color: "red"
                            }
   property var theArray: new Array()
   property var theDate: new Date()
另外,任何的QML對象類型均可以被用做property屬性類型。例如:
property Item someItem
    property Rectangle someRectangle

這對於自定義QML類型也是適用的。

  • 自定義屬性的調用方式:
    屬性所屬控件id. propertyName
屬性別名
  • 屬性別名就是保存對另外一個屬性的引用。不像普通屬性的定義,普通屬性的定義須要分配一個新的,惟一的存儲空間,而一個屬性別名僅僅是鏈接到了屬性上。
    屬性別名的定義根屬性定義差很少,只是屬性別名須要使用alias關鍵字代替屬性定義中的property類型,右邊的值必須是合法的引用別名:
    屬性別名的語法格式以下:
property alias <name> : aliasreference

name是咱們自定以的屬性名,aliasreference是屬性別名所引用的那個屬性或對象,也就是說屬性別名能夠引用自一個單一的屬性,也能夠引用自一個複雜的對象。屬性綁定是動態的,但不是雙向的,而經過屬性別名可達到動態、雙向的效果,即修改name和aliasreference中任一個的值,與之關聯的另外一個屬性值也會隨之改變。
須要注意的是,若是屬性別名與已有的屬性名相同,就會把已有的屬性覆蓋掉,當咱們再使用這個屬性的時候,實際上使用的是咱們自定義的那個屬性,例如:

Rectangle {
    id: rootRect
    // 引用屬性
    property alias color: blueRect.color
   // 引用對象
    property alias theRect: blueRect

    color: "red"

    Rectangle {
        id: blueRect
        color: "#1234ff"
    }
}
  • 若是爲一個已經存在屬性建立一個同名的屬性別名,這就會覆蓋已經存在的屬性。
    上面的代碼中定義的color屬性,會替代Rectangle原有的color屬性,爲了不已有屬性被覆蓋的問題,定義的屬性別名不能與已有屬性相同。
  • 若所引用的屬性不是已經存在屬性,則定義的屬性別名要與引用的屬性名稱相同。 例如:
Rectangle {
    id: rootRect
    property alias count: nameList.count
    property alias currentIndex: nameList.currentIndex
    color: "red"
    ListView{
        id: nameList
    }
}

Rectangle沒有count和currentIndex屬性,則要將屬性別名與引用屬性名設置成同樣。

  • 只有在組件徹底初始化以後屬性別名纔會被激活。若是未初始化的別名被引用了就會產生錯誤。
  • 爲一個屬性別名產生屬性別名也會致使錯誤,例如:
property alias sureBtn: testBtn
property alias text: sureBtn.text
Button{
    id: testBtn
    width: 100
    height: 40
    text: "1233"
}
Component.onCompleted: console.log("text="+text)

產生的錯誤提示: Invalid alias reference. Unable to find id "sureBtn"

只讀屬性

任何對象的定義均可以使用readonly關鍵字定義只讀屬性,使用下面的語法:

readonly property <propertyType> <propertyName> : <initialValue>

只讀屬性必須在初始化的時候指定值。一旦只讀屬性被初始化了,它就不可能再被賦值了,不管是賦值(使用」=」)仍是其它的方式。
例如,下面的Component.onCompleted代碼塊就是非法的:

Item{
    id: root
    readonly property int chiledNum: 10
    width: 100
    height: 40
    Component.onCompleted: root.chiledNum = 20
}
信號

信號就是當某些事件發生的時候從對象類型中發出通知:例如,一個屬性改變,一個動畫開始或者中止,當一個圖片下載完成,或者MouseArea類型當用戶點擊的時候就會發射一個點擊信號。
當一個信號發射了,對象能夠經過signal handler被通知。一個signalhandler的定義語法爲on 是信號的名稱,首字母要大寫。Signalhandler必須在發射該信號的對象定義的內部實現,而且signalhandler必須包括JavaScript代碼塊,當signal handler被調用的時候該代碼塊就會被執行。
例如,MouseArea對象的定義中能夠定義onClicked類型的signal handler,當MouseArea被點擊了該signal handler就會被調用,使得控制檯打印出消息:

Item{
    id: root
    width: 100
    height: 40
    MouseArea{
        anchors.fill: parent
        onClicked: console.log("Click!")
    }
}

qml文件中,定義信號signal的語法:

signal <signalName>[([<type> <parameter name>[, ...]])]

信號通常是相關聯的事件觸發的,信號名由英文字母和_組成,已小駝峯的形式命名。

  • 信號的命名規則遵循屬性的命名規則,以小駝峯的形式命名。
  • 若是信號不帶參數,則一概不使用()
  • 若是信號帶參數,參數要寫參數類型。
    信號參數的命名規則:
    msg+大駝峯形式
    必須以「msg」開頭,便於標識是信號參數。
    例子:
signal clicked
signal hovered(string msgInfo)
signal activated(real msgXPosition, real msgYPosition)

信號的調用方式:信號所屬控件id.信號

js代碼

自定義的js函數,能夠帶參數,也能夠不帶出參數,且參數不用指明參數類型,由於函數的參數類型默認是萬能的var類型。
函數名由字母和_組成,且首字母必須是小寫,即以小駝峯的形式命名,例如:

function addZero(num){
    if(num < 10)
        return "0"+num
    else
        return num
}
  • 函數返回時不要使用圓括號。
  • 當定義的js函數,僅能在本qml文件使用,即便私有函數時,此函數的命名纔用到_, 且是以雙下劃線(__)開始 + 小駝峯的方式命名,例如:
function __factorial(a) {
    a = parseInt(a);
    if (a <= 0)
        return 1;
    else
        return a * factorial(a - 1);
}
  • qml文件中js函數的調用:函數所在控件的id.函數名()
js文件

當一個qml文件中的js代碼較多即:js函數代碼超過80行時,應根據其分類或應用邏輯單獨做成一個js文件,再將js文件導入qml文件。
js文件的導入方法:

  • qml中導入的js文件必需要有別名,別名的命名規則:
    以大駝峯的形式命名
    由js文件名中除了_和impl之外的字母組成,例如:
import "jsfile_impl.js" as Jsflie
  • 在js文件中導入另外一個js文件的2種方法 :
.import "filename_imp.js" as Filename
Qt.include "filename.js"`
布爾表達式
  • 在布爾表達式中,邏輯運算符 && 和|| 兩邊的條件表達式根據邏輯須要添加圓括號()
狀態機
  • 在qml中,狀態是定義在state類型中的一系列屬性配置,不一樣的配置可能有不一樣的做用,爲了方便起見,State元素都有一個when屬性,能夠綁定表達式來改變狀態,當綁定的表達式評估爲true,狀態改變;當表達式評估爲false,狀態會退回到default state。
  • 顯示一些UI控件,隱藏另外一些。
StateGroup {
    states: [
        State {
            name: "xxx"
            when: visible
            PropertyChanges {
                target: xxxBtn
                visible: true
            }
            PropertyChanges {
                target: yyyBtn
                visible: true
            }
            PropertyChanges {
                target: zzzBtn
                visible: fasle
            }
        }
    ]
}
  • 啓動、暫停、中止動畫。
StateGroup {
    states: [
        State {
            name: "start"
            when: 0 == animationState
            PropertyChanges {
                target: imageAnimation
                running: true
            }
        },
        State {
            name: "pause"
            when: 1 == animationState
            PropertyChanges {
                target: imageAnimation
                paused: true
            }
        },
        State {
            name: "stop"
            when: 2 == animationState
            PropertyChanges {
                target: imageAnimation
                running: false
            }
        }
    ]
}
  • 改變某個特定Item的property的值。
StateGroup {
    states: [
        State {
            name: "color"
            when: bChanged
            PropertyChanges {
                target: rootRect
                color: "red"
            }
        },
        State {
            name: "enabled"
            when: disabled
            PropertyChanges {
                target: rootRect
                enabled: false
            }
        }
    ]
}
  • 顯示一個不一樣的view或screen。
StateGroup {
   states: [
       State {
           name: "xxx"
           when: 0 == loaderState
           PropertyChanges {
               target: xxxLoader
               source: "Xxx.qml"
           }
       },
       State {
           name: "yyy"
           when: 1 == loaderState
           PropertyChanges {
               target: xxxLoader
               source: "Yyy.qml"
           }
       },
       State {
           name: "zzz"
           when: 2 == loaderState
           PropertyChanges {
               target: xxxLoader
               source: "Zzz.qml"
           }
       }
   ]
}
  • 在某種新的狀態下執行某些腳本。
// statetest.js
function getColor()
{
    return "green";
}

// test.qml
import "statetest.js" as StateTest
Rectangle{
    id: rect
    width: 50; height: 50
    color: "red"
    MouseArea {
        anchors.fill: parent
        onClicked: rect.state = "changedColor"
    }
StateGroup {
    states:
        State {
            name: "changedColor"
            StateChangeScript{
                name: "myScript"
                script: rect.color = StateTest.getColor()
            }
        }
    }
}
  • 向用戶呈現不一樣的操做和功能
Rectangle {
    id: rect
    width: 120; height: 120
    color: "black"
    Rectangle { id: myRect; width: 50; height: 50; color: "red" }
    StateGroup {
        states:
            State {
                name: "reanchored"
                AnchorChanges { // 改變 myRect 的anchors屬性
                target: myRect
                anchors.top: rect.top
                anchors.bottom: rect.bottom
            }
            PropertyChanges {
                target: myRect
                anchors.topMargin: 10
                anchors.bottomMargin: 10
            }
        }
    }
    // 鼠標事件
    MouseArea {
        anchors.fill: parent
        onClicked: rect.state = "reanchored"
    }
}
  • 把指定的item換一個item父節點
Item {
        width: 200
        height: 100
        Rectangle {
            id: redRect
            width: 100
            height: 100
            color: "red"
        }
        Rectangle {
            id: blueRect
            x: redRect.width
            width: 50
            height: 50
            color: "blue"
            states: State {
            name: "reparented"
            ParentChange {
                target: blueRect
                parent: redRect
                x: 10
                y: 10
            }
        }
        MouseArea {
            anchors.fill: parent
            onClicked: blueRect.state = "reparented"
        }
    }
}
  • states中每一個state之間的觸發條件與PropertyChanges中的屬性之間不要有關聯,如有關聯,可能會造成死循環。

  • 在qml中使用states時,必定要加上父層StateGroup,這樣能夠避免與原始控件中state名相同的state相沖突,產生沒法預料的問題。

  • 能用條件運算符替代states的地方,儘可能用條件運算符,不要用states。條件運算符的執行速度比state快。

StateGroup {
    states:
        State {
            name: "name"
            when: bChanged
            PropertyChanges {
                target: root
                color: "red"
            }
        }
}

應修改成:

color: bChanged ? "red" : "white"`
  • 同一個State中有多個PropertyChanges,PropertyChanges的target不能設置同樣,不然只執行第一個PropertyChanges。

例如:
錯誤的寫法

StateGroup {
    states:
        State {
            name: "name"
            when: bChanged
            PropertyChanges {
                target: root
                color: "red"
            }
            PropertyChanges {
                target: root
                border.color: "red"
            }
        }
}

應該修改成:

StateGroup {
    states:
        State {
            name: "name"
            when: bChanged
            PropertyChanges {
                target: root
                color: "red"
                border.color: "red"
            }
        }
}

內部組件

與「根組件定義」相同,可是其屬性、信號、方法命名需添加雙下劃線("__")前綴。
好比:

Item {
        id: root
        width: 800
        height: 480
        Item {
            id: subItem

            property bool __updateState:false

            signal __clicked

            function __doSomething(x)
            {
                return x+subItem.x
            }

            width: 400
            height: 400

        }
    }

註釋

爲了提升qml代碼的可讀性和便於後期維護,註釋是必不可少的。

文件功能註釋

文件功能註釋是對此qml大概功能的一個概述,若此qml文件還做爲控件別的qml文件使用,則還有寫出大概的使用方法。
例以下面是combobox.qml文件功能的註釋:

/*!
將一個model的數據如下拉框列表的形式顯示,經過選擇下拉框列表數據,改變當前顯示的數據
    \qml
       ComboBox {
           width: 200
           model: [ "Banana", "Apple", "Coconut" ]
       }
    \endqml
*/

註釋以「/!」開始,以「 /」 結束,包含的對文件功能的說明,和控件的使用方法,使用用例以「\qml」開始,以「\endqml」結束。

自定義屬性、信號、方法註釋

  • 自定義的屬性、信號、方法必須添加註釋。
    自定義屬性、信號、方法註釋格式爲:「/! /」,寫在其定義的上一行,例如:
/*! ComboBox下拉框列表當前選中的index值 */
    property int currentIndex: 0

其餘註釋

這裏的其它註釋是指除文件功能註釋和自定義屬性、信號、方法註釋外的其它須要註釋的代碼。
代碼註釋格式爲:「 // xxxxxxxxx 」,寫在被註釋代碼上方,例如:

// temporarily set fillIndex to new item
fillIndex = __items.length

補充說明

object properties

  • 一行寫一條語句

通常屬性設置的順序爲:

id: rootRect
x: 10
y: 10
width: 100
height: 100
...

組屬性的設置

在對控進行屬性設置時,若是有同一類組的多個屬性須要設置,爲了提升代碼可讀性,則使用組的提示符,而不是點的運算符號。
例如:

anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: 10
anchors.leftMargin: 10

應該改寫成:

anchors {
    top: parent.to
    left: parent.left
    topMargin: 10
    leftMargin: 10
}

Qml中和c++中均可以處理的邏輯

在qml文件中,有許多的邏輯處理既能夠在qml中完成,也能夠在c++中處理,原則是qml代碼只處理界面顯示邏輯,其它邏輯能在c++中處理的,一概在c++中處理,這樣有利於提升qml的加載速度 。

MouseArea{ anchors.fill: parent }的特殊用法

MouseArea除了處理Item的鼠標響應,還有一個典型的用途是,MouseArea { anchors.fill: parent }可以屏蔽鼠標事件的滲透。
例如:

// main.qml
   Rectangle{
      width: 800
      height: 480
      Button{
            width: 150
            height: 50
            text: "Button"
            onClicked: {
                if(ld.source === 「 」){
                    ld.source= "TestChild.qml"
                }
            }
      }
      Loader{
        id:ld
      }
   }

   // TestChild.qml
   Rectangle{
      width: 800
      height: 480
   }

當TestChild界面加載後,在TestChild界面上與main界面的Button所處位置的重疊處點擊,會觸發main界面Button的點擊事件,
這就是一個界面的鼠標事件參透到另外一界面。爲了不鼠標滲透事件的發生,TestChild.qml應該修改成:

Rectangle{
      width: 800
      height: 480
      MouseArea { anchors.fill: parent }
   }

注意:MouseArea { anchors.fill: parent }要做爲TestChild界面的第一個子控件,才能屏蔽整個TestChild的鼠標滲透,又不影響TestChild界面中其它可操做控件事件。

經常使用控件的縮寫

1.Button -> btn
1.CheckBox -> chk
1.ComboBox -> cmb
1.RadioButton -> rdo
1.Text -> txt
1.Label -> lbl
1.Image -> img
1.DateTimePicker -> dtp
1.ListView -> lvw
1.ToolTip -> tip
1.GroupBox -> grp
1.Panel -> pnl
1.Calendar -> cal
1.TreeView ->trvw
1.ListView->lvw
1.GridView -> gvw
1.Repeater->rpt
1.Menu ->mnu
1.ProgressBar ->prg

屬性的綁定

所謂屬性綁定,就是創建目標對象對其它對象的依賴關係,當其它對象發生變化時,目標對象也會變化,自動更新相關的屬性值,達到動態屬性的效果,例如:

Item {
        id: root
        width: 800
        height: 480
        focus: true
        Keys.enabled: true
        // 從新綁定
        Keys.onEnterPressed: redRect.width = Qt.binding(function() {return parent.width/2})
        Rectangle {
            id: redRect
            anchors.fill: parent
            width: parent.width/3  // 綁定
            height: 100
            color: "red"
        }

        Button{
            width: 60
            height: 30
            text: 「Button」
            onClicked: redRect.width = 150    // 綁定解除
        }
    }

上述例子中,redRect的width屬性最初綁定到了root的width屬性上,redRect的width會隨着root的width變化而變化;Button按下後,redRect的width屬性綁定解除;Enter鍵按下後,redRect的width屬性從新綁定;Button再次按下後,redRect的width屬性綁定解除。
也就是說若是屬性綁定已經完成,那麼在別的地方從新給這個屬性賦值時,不論是賦個靜態值,仍是想換個別的屬性綁定表達式,都會破壞原來的綁定關係,而新的值也不會有動態屬性的效果。

Keys的載體

Keys是專門用來處理鍵盤事件KeyEvent的,它定義了許多針對特定按鍵的信號,例如digit0Pressed(KeyEvent event)、spacePressed(KeyEvent event)等,不過使用pressed(KeyEvent event)和released(KeyEvent event)這兩個普通的信號就能夠處理大部分按鍵事件了,信號的參數類型是KeyEvent,參數名是event,包含了按鍵的詳細信息。
這裏說所的載體是指Keys所屬的父組件,Keys的載體必須是Item,或從Item繼承而來,不能是Window或從Window繼承而來的組件,不然Keys無效。
例如:

Window {
      visible: true
      width: 360
      height: 360
      Keys.enabled: true;
      Keys.onEscapePressed: Qt.quit()             // 沒有功能: 不退出
Window {
      visible: true
      width: 360
      height: 360
      Item{
            anchors.fill: parent
            focus: true
            Keys.enabled: true;
            Keys.onEscapePressed: Qt.quit()             // 有功能: 退出
      }

Loader

QML的Loader元素常常備用來動態加載QML組件。可使用source屬性或者sourceComponent屬性加載。這個元素最有用的地方是它能在qml組件須要的時候再建立,即延遲建立QML的時間。
加載與被加載組件中都有相同的事件,那麼須要設置Loader的屬性focus爲true,且設置被加載組件 focus: true才能讓事件不被傳播到被加載組件。

main.qml
Item {
    property bool isFirst : false;
    width: 200
    height: 200

    Loader {
        id: pageLoader
        source: "Page2.qml"
        focus: true
    }

    Keys.onPressed: {
        console.log("Captured: ", event.text);
        event.accepted = true;
    }
}


// Page2.qml

Rectangle {
    width: 100
    height: 62
    Text {
        anchors.centerIn: parent
        text: "Page2 Test"
    }
    focus: true
    Keys.onPressed: {
        console.log("Loaded item captured: ", event.text)
        event.accepted = true
    }
}

若將main.qml中Item的focus設置爲true,則上述代碼的只有main響應按鍵消息。

  • 若是source或者sourceComponent更改了,任何先前實例化的項目都將被自動銷燬。

  • 將source設置爲空字符串或者sourceComponent設置爲undefined,則銷燬當前加載的項目,釋放資源,並將Loader設置爲空。

  • Loader出來的qml界面,在界面關閉時,必定要清空Loader資源。

qml的目錄結構

在獨立項目或者Roshan插件中,qml的目錄結構都是相似的。
資源

qml.qrc
components
img
views

main.qml

  • components文件夾用來放置項目或插件的專有控件。
  • img文件夾用來放置項目或插件的圖片資源。
  • view文件夾用來放置用來放置除專有控件、圖片資源和main.qml外的其餘文件。

model

QML中,model是爲ListView,GridView和Repeater等元素來提供要顯示數據的數據模型.這些元素須要一個爲模型中的每一項數據生成一個實例的代理組件(delegate component).給代理提供的數據經過叫作角色的數據綁定到代理.
例以下述代碼中,ListModel有兩個角色:text 和 age,與代理模型Text的屬性text的名稱相沖突。
在這種狀況下,若是直接在代理中綁定角色名稱,則代理Text的text不會顯示模型中text角色值,而是顯示它自身的屬性值。爲了不這種衝突的產生,在角色前面加上model.便可正常顯示。

Item{
        width: 200
        height: 200
        ListView{
            id: testList
            anchors.fill: parent
            model: testModel
            delegate: Text{
                width: lst.width
                height: 30
               // text: text + "-" + age
                text: model.text + "-" + model.age
            }
        }
        ListModel{
            id: testModel
            ListElement{
                text: "ccw"
                age: 12
            }
            ListElement{
                text: "ym"
                age: 13
            }
            ListElement{
                text: "zfb"
                age: 35
            }
            ListElement{
                text: "ded"
                age: 30
            }
        }
    }

其它

  1. js代碼中,可以用條件運算符(? :)代替 if...else...地方,要用條件運算符,這樣是代碼更簡潔明瞭。

  2. js中「==」和「===」的區別:
    ==用於通常比較,在比較的時候能夠轉換數據類型。
    ===用於嚴格比較,只要類型不匹配就返回flase。

  3. 當一個qml文件中,代碼行達到200至300行時,要從其qml文件中分解出子qml文件。
    這樣能夠避免出現控件關聯複雜,篇幅較長的代碼。

  4. 只有一條語句的代碼塊,寫成一行,例如:

  MouseArea { anchors.fill: parent }

在信號處理代碼中,若是也只有一條執行語句,則寫成一行,且不須要{},例如:

onPressed: {
        rootRect.color= "gray"
    }

應該寫成:

onPressed: rootRect.color= "gray"
相關文章
相關標籤/搜索