1. 程式人生 > >QML 靜態值與屬性繫結

QML 靜態值與屬性繫結

簡述

可以為 QML 物件中的屬性分配兩種型別的值 - 靜態值和繫結表示式,後者也稱為屬性繫結。

  • 靜態值:一個不依賴於其他屬性的常數值。
  • 繫結表示式:一個用於描述屬性間依賴關係的 JavaScript 表示式。

屬性繫結是 QML 的一個核心特性,允許指定不同物件屬性之間的依賴關係。當屬性的依賴項(屬性繫結中的變數)的值發生改變時,屬性將根據指定的關係自動更新。

|

靜態值

所謂靜態值,就是一個不依賴於其他屬性的常數值。例如:width : 100,其中 100 就是一個靜態值。

下面的示例,將 Rectangle 的 width 和 height 均分配為靜態值。

這裡寫圖片描述

import QtQuick 2.3
Rectangle { // 初始化賦值 - 靜態值 width: 200 height: 200 Rectangle { // 初始化賦值 - 靜態值 width: 100 height: 100 color: "blue" } }

既然藍色 Rectangle 的 width 和 height 都是靜態值,那麼當父 Rectangle 大小發生變化時,藍色 Rectangle 的大小必然不會改變。

屬性繫結

屬性繫結,簡單的理解就是一個繫結表示式,用於描述屬性之間的依賴關係。例如:width : parent.width / 2

QML 引擎作為屬性繫結的幕後推手,在時刻監視屬性的依賴項,當檢測到任何依賴項的值發生改變後,就會自動重新計算繫結表示式,併為屬性分配新的結果。

使用屬性繫結

要建立一個屬性繫結,需要為屬性分配一個 JavaScript 表示式,該表示式將計算所需的值。最簡單的情況,繫結是對另一屬性的引用。

下面的示例,將藍色 Rectangle 的 width 繫結到其 parent 的 width:

這裡寫圖片描述

import QtQuick 2.3

Rectangle {
    width: 200
    height: 200

    Rectangle {
        width: parent.width
        height: 100
color: "blue"
} }

每當父 Rectangle 的 width 發生變化,藍色 Rectangle 的 width 就會自動更新為相同的值。

繫結可以包含任何有效的 JavaScript 表示式或語句,因為 QML 使用了一個符合標準的 JavaScript 引擎。繫結可以訪問物件屬性、呼叫方法、並使用內建的 JavaScript 物件(例如:Date、Math)。下面是上述示例的其他可能性繫結:

// 訪問物件屬性
width: parent.width / 2

// 使用內建的 JavaScript 物件 Math
width: Math.min(parent.width, parent.height)

// 使用三目運算子
width: parent.width > 100 ? parent.width : parent.width /2

// if-else 程式碼塊中的 return 關鍵字可有可無
width: {
    if (parent.width > 100)
        return parent.width
    else
        return parent.width / 2
}

// 呼叫方法
height: someMethodThatReturnsWidth()

在語法上,繫結允許具有任意複雜性(例如:涉及多行或命令迴圈)。但是,如果繫結過於複雜,可能會降低程式碼效能、可讀性、和可維護性。比較好的方法是:重新設計具有複雜繫結的元件,或者至少將繫結轉換為單獨的函式。

從 JavaScript 建立屬性繫結

具有繫結的屬性將根據需要自動更新,但是,如果稍後從 JavaScript 語句為該屬性重新分配一個靜態值,則將會移除繫結。

例如,下面的藍色 Rectangle 最初確保其 width 總是其 parent 的 width 的 1/4。但是,當按下空格鍵時,parent.width / 2 將作為靜態值賦值給 width。隨後,即使其 parent 的 width 發生變化,其 width 也將保持不變,因為靜態值的分配移除了繫結。

這裡寫圖片描述

import QtQuick 2.3

Rectangle {
    width: 200
    height: 200

    Rectangle {
        id: rect
        width: parent.width / 4
        height: 50
        color: "blue"

        focus: true
        Keys.onSpacePressed: {
            width = parent.width / 2
        }
    }
}

如果目的是為了給藍色 Rectangle 一個固定的 width 並停止自動更新,那麼這沒有任何問題。但是,如果是為了給 width 和其 parent 的 width 建立一個新的關係,那麼新的繫結表示式必須被包裹在 Qt.binding() 函式中:

這裡寫圖片描述

//...
Keys.onSpacePressed: {
    width = Qt.binding(function() { parent.width / 2 })
}
//...

現在,按下空格鍵後,矩形的高度將繼續自動更新,始終為其 parent 的 width 的 1/2。

在屬性繫結中使用 this

當從 JavaScript 建立一個屬性繫結時,this 關鍵字可用於引用接收繫結的物件,這有助於解決屬性名稱產生的歧義。

例如,下面的 Component.onCompleted 處理程式在 Item 的範圍內定義。此範圍內,width 是指 Item 的 width,而不是 Rectangle 的 width。要將 Rectangle 的 height 繫結到其自身的 width,繫結表示式必須顯式地引用 this.width(或者 rect.width):

import QtQuick 2.3

Item {
    width: 200
    height: 200

    Rectangle {
        id: rect
        width: 100
        color: "blue"
    }

    Component.onCompleted: {
        rect.height = Qt.binding(function() { return this.width * 2 })
        console.log("rect.height = " + rect.height) // 列印 200, 而非 400
    }
}

可以看出,this 指向的是接收 Qt.binding() 的返回值的物件。在這裡,可以理解為 rect 表示的物件。

注意: this 的值不是在屬性繫結之外定義的。