解讀QML之四

來源:互聯網
上載者:User
                                       
 解讀QML之四
QML對象屬性

        每一個QML物件類型都定義了一系列屬性。每建立一個該物件類型的執行個體,該執行個體的這些屬性也自動被建立了。接下來我們討論幾種不同類型的屬性。

id屬性

           每一個QML物件類型都有一個唯一確定的id屬性。這個屬性是由QML語言自身提供的,並且在QML物件類型中不能被重定義和重載。

        我們必須為id屬性指定一個值允許該對象被唯一標示並且可用於被其它對象引用。Id屬性值必須以小寫字母或者底線開始,只能包含字母,數字和底線等字元。

        下面是一個TextInput對象和一個Text對象,TextInput對象的id屬性值為”myTextInput”。Text對象的text屬性值通過myTextInput.text被設定為和TextInput對象的text屬性值一樣。


         我們以後可以在該組件可見域內通過id屬性引用該對象。因此id屬性值在組件可見域內必須是唯一的。

         一旦對象執行個體被建立了,那麼id屬性值就不能被改變。Id屬性看起來像普通屬性,但是並非是真正的普通屬性,我們對它應用特殊的語義,例如:在上面的例子中我們不能使用myTextInput.id。

property屬性

        一個property是對象的一個屬性,可以被賦為靜態值或者是綁定到動態運算式上。一個property的值可以被其它的對象讀取。一般情況下,property屬性也可以被其它對象修改,除非該QML類型明確指定該property屬性不能被修改。

 【定義property屬性】

   一個property屬性可以在C++中定義,並且通過Q_PROPERTY註冊到QML類型系統。當然,我們也可以在QML文檔中通過如下文法自訂對象的property屬性:


         通過這種方式,一個對象可以將一些特定的值暴露給其它對象,或者是更加簡便的維護一些內部狀態。

         Property屬性的名稱必須以小寫字母開頭,且只能包含字母,數字和底線。JavaScript的保留關鍵字不能作為property屬性的名稱。Default關鍵字是可選的,對於default以及default屬性修改者的詳細資料稍後討論。

         定義一個自訂的property屬性也就為該property屬性隱式的建立了一個value-change訊號,也就是關聯了一個名為on<PropertyName>Changed的signal handler。<PropertyName>就是property屬性的名稱,而且首字母要大寫。

         例如:下面就定義了兩個property屬性,並且實現了其signalhandler:


【自訂property屬性的合法類型】

      QML基本類型中的枚舉類型都可以作為自訂property屬性類型。例如:下面都是合法的property屬性聲明:


        一些QtQuick模組提供的基本類型是不能作為property類型的,除非在QML文檔中匯入QtQuick模組。

       var基本類型是通用的類型,可以儲存任意類型的值,包括lists和objects:


        另外,任何的QML物件類型都可以被用作property屬性類型。例如:


        這對於自訂QML類型也是適用的。如果在ColorfulButton.qml檔案中定義了一個QML類型,那麼ColorfulButton類型的property屬性也是合法的。

  【合法的property屬性值】

我們可以通過兩種方式為定義的property屬性的值:

  *初始化

  *賦值

  值可以是靜態值也可以是綁定運算式。

  {初始化}

    Property屬性初始化:


     我們可以在定義property屬性的時候,也進行初始化賦值:


       初始化賦值舉例如下:


{賦值}

     我們可以使用JavaScript代碼給property屬性賦值,如下:


     舉例如下:


【合法的property值】

     正如之前提到的,我們可以給property屬性賦兩類值:靜態值和綁定運算式:


     樣本:


        在許多情況下,string類型的值可以自動被轉換為許多不同類型的值,因為QML提供了string類型到其它類型的轉換(這也就是為什麼你可以給color屬性賦值”red”)。

         必須特別注意,綁定到一個運算式的情況下,右邊的運算式必須的Qt.binding()函數的傳回值,該函數返回合適的實值型別。一個運算式可以在property屬性初始化的時候直接賦值,而不需要使用那個函數(實際上使用函數還會導致錯誤)。

 【型別安全】

       屬性都是型別安全的。給屬性賦值必須是類型匹配的。

       例如,下面的賦值就會導致一個錯誤:


         如果在運行時的時候給屬性賦類型錯誤的值,那麼賦值也不會成功還會產生一個錯誤。

        正如在之前提到過的,一些屬性類型並沒有很好的類型來表達其值,這個時候QML引擎提供了很好的string類型轉換。例如:color屬性,該屬性儲存區的實值型別應該是color類型而不是string類型,但是你卻可以給它指定string類型的值,而不會產生錯誤。

【特殊的property屬性類型】

     對象清單類型的property屬性

     List類型的property屬性也可以被賦予QML物件類型列表的值。賦值的形式如下:


        例如:Item類型有一個狀態屬性,可以用於儲存State物件類型的列表。下面的代碼用於初始化該列表:


        如果列表僅僅包含一項,那麼方括弧可以省略:


        我們可以像下面這樣定義對象清單類型的property屬性:


      List類型的屬性聲明舉例如下:


       如果你希望聲明一個屬性用於儲存列表值,但不一定是儲存QML物件類型值,這個時候你就需要聲明var的property屬性。

【分組的屬性】

        在某些情況下,我們可以將屬性根據邏輯分為子屬性群組。這些子屬性可以通過”.”或者是組來賦值。

        例如:Text類型有一個font的組屬性。在下面,第一個Text對象使用”.”初始化font的值,第二個則是使用組來賦值:


        組屬性類型都是基本的類型。這些基本類型一部分是由QML語言提供的,另外一部分則是由Qt Quick模組提供的。

 【屬性別名】

         屬性別名就是儲存對另一個屬性的引用。不像普通屬性的定義,普通屬性的定義需要分配一個新的,唯一的儲存空間,而一個屬性別名僅僅是串連到了屬性上。

         屬性別名的定義根屬性定義差不多,只是屬性別名需要使用alias關鍵字代替屬性定義中的property類型,右邊的值必須是合法的引用別名:


        不像普通的屬性,一個別名僅僅可以引用對象或者是對象的屬性。

        例如:下面的Button類型有一個buttonText屬性別名,連結到子Text對象的text屬性:


       下面的代碼會建立一個Button,並且定義文本字串:


        修改了buttonText,就直接修改了textItem.text的值,它不會修改其它的值。如果buttonText不是屬性別名,那麼修改它的值是不會修改顯示的文本的,因為屬性綁定不是雙向的。

【考慮屬性別名】

     只有在組件完全初始化之後屬性別名才會被啟用。如果未初始化的別名被引用了就會產生錯誤。另外,為一個屬性別名產生屬性別名也會導致錯誤:


        我們可以為一個已經存在屬性建立一個同名的屬性別名,這就會覆蓋已經存在的屬性。例如:下面的QML類型有一個color屬性別名,跟Rectangle內建的屬性Rectangle::color屬性:


【default屬性】

         一個對象定義可以包含一個default屬性。如果一個對象()子物件定義在另一個對象(父物件)之內而沒有賦值給該父物件的任何屬性,那麼該子物件就是該父物件default屬性的值。聲明為default屬性需要使用default關鍵字。

        例如下面的MyLabel.qml檔案中的對象就有一個someText的預設屬性:


       我們可以在MyLabel對象定義中為someText預設屬性賦值:


        上面兩個等同於下面一個:


       然而,由於someText屬性被標記為預設屬性,因此我們就沒有必要顯示的將Text對象賦值給這個預設屬性。

       你也可能注意到了子物件可以添加到任何基於Item的類型,而不需要明確將它們添加到子屬性上。這是因為Item的預設屬性是data屬性,任何添加到Item中的對象都自動添加到它的子物件列表。

        預設屬性對於重新指定子物件是十分有用的。可以看看TabWidget樣本,該樣本就是使用預設屬性自動重新指定TabWidget的子物件作為它的子物件列表。

 【唯讀屬性】

   任何對象的定義都可以使用readonly關鍵字定義唯讀屬性,使用下面的文法:


       唯讀屬性必須在初始化的時候指定值。一旦唯讀屬性被初始化了,它就不可能再被賦值了,無論是賦值(使用”=”)還是其它的方式。

       例如,下面的Component.onCompleted代碼塊就是非法的:


注意:一個唯讀屬性是不能聲明為預設屬性或者是屬性別名的。

 【屬性修改對象】

       屬性可以有屬性值修改對象與它們關聯。我們可以像如下的這樣定義屬性修改對象執行個體,與特定的屬性關聯:


        需要注意的是,上面的文法實際上一個對象聲明,將會執行個體化一個對象操作已存在的屬性。

       特定的屬性修改類型只能應用到特定的屬性類型上,但是這並不是被語言強制的。例如:QtQuick模組提供的NumberAnimation類型僅僅影響數字類型(例如int或者real)屬性。如果將NumberAnimation使用到非數字類型屬性將不會引起錯誤,但是非數字屬性將不會產生動畫。屬性修改類型的動作是與特定屬性的實現緊密相關的。

 Signal屬性

        訊號就是當某些事件發生的時候從物件類型中發出通知:例如,一個屬性改變,一個動畫開始或者停止,或者當一個圖片下載完成。例如,MouseArea類型當使用者點擊的時候就會發射一個點擊訊號。

        當一個訊號發射了,對象可以通過signal handler被通知。一個signalhandler的定義文法為on<Signal>,<Signal>是訊號的名稱,首字母要大寫。Signalhandler必須在發射該訊號的對象定義的內部實現,並且signalhandler必須包括JavaScript代碼塊,當signal handler被調用的時候該代碼塊就會被執行。

         例如,MouseArea對象的定義中可以定義onClicked類型的signal handler,當MouseArea被點擊了該signal handler就會被調用,使得控制台列印出訊息:


【定義Signal屬性】

        我們可以使用Q_SIGNAL在C++的類中定義Signal屬性並註冊到QML類型系統。可選的,我們也可以在QML文檔中使用如下文法定義signal屬性:


        在一個類型塊中定義兩個同名的訊號或者方法將會產生錯誤。然而,我們可以使用已經存在的訊號類型定義新的訊號(這會導致之前的訊號不可見)

       下面就是一個訊號定義的樣本:


         如果一個signal沒有參數,那麼”()”就是可選的。如果使用了參數,那麼參數的類型就必須指定,例如上面的actionPerformed訊號中的string和val參數。允許使用的參數類型根之前描述的定義property屬性中的一樣。

       要發射一個訊號,那麼就會調用一個方法。任何和訊號關聯的signal handler都會在訊號被發射的時候執行,並且handlers可以使用定義的訊號參數的名字和擷取預期的參數。

【屬性改變訊號】

        QML類型也提供內建的屬性改變訊號,當屬性值被改變的時候這些訊號就會被發射。接下來我們就來介紹訊號的好處以及如何使用。

【Signal Handler屬性】

        Signal handlers是特殊的方法屬性類型,當訊號發射了,與訊號關聯的特定方法就會被調用。在QML中添加一個訊號就會自動添加一個與之關聯的signalhandler,預設情況下該函數就會是空實現。用戶端可以提供自己的實現來實現程式邏輯:

       考慮下面的SquareButton類型,該類型是SquareButton.qml檔案中定義的,定義了兩個訊號:activated和deactived:


        這些訊號可以在同一目錄下的其他QML檔案中的任何SquareButton對象擷取,用戶端也提供了signalhandler實現:


【屬性改變Signal Handler】

        屬性改變的Signal handler文法如下on<Property>Changed,<Property>就是屬性的名稱,首字母要大寫。例如,儘管TextInput類型文檔沒有定義textChanged訊號,但是這個訊號因為TextInput有一個text屬性而可用。因此我們也就可以實現onTextChanged signal handler,當屬性值被改變的時候就會調用該signal handler:


方法屬性

           一個對象的方法就是在執行一些處理或者觸發一些事件的時候被調用的。當一個方法串連到一個訊號時,當訊號被發射的時候,這些方法就會被執行。

【定義方法屬性】

        我們可以通過在C++的類的函數使用Q_INVOKABLE註冊到QML類型系統或者是在C++類中註冊為Q_SLOT。可選的,我們也可以在QML文檔中自訂方法添加到對象中:


       方法可以添加到QML類型以定義單獨的可重用的JavaScript代碼。這些方法可以在內部被調用或者是被外部對象調用。

       不像訊號,這裡不用定義參數的類型,因為它們預設為var類型。

        在同一個類型塊中視圖定義兩個同名的方法或者是訊號都會導致錯誤。然而,我們可以使用已存在的方法的名稱定義新的方法(這會導致已存在的方法不可用)

        下面的Rectangle類型有一個calculateHeight()方法,當指定height值的時候該方法就會被調用。

         如果方法有參數,那麼我們可以在方法中通過參數名訪問它們。例如,MouseArea被點擊,那麼就會調用moveTo()方法,可以使用newX和newY設定文本的新位置:


附加屬性和附加SignalHandler

        附加屬性和附加的訊號處理機制允許對象使用那些對象不可引用的外部屬性和訊號處理者。這允許對象訪問那些與單個對象關聯的屬性和訊號。

         一個QML類型實現可以選擇建立附加的特定屬性和訊號。執行個體化這種類型就會在運行時建立,允許這些對象訪問屬性和訊號。

引用附加的屬性和handlers文法如下:


        例如:ListView類型有一個附加的屬性ListView.isCurrentItem,該屬性可以被ListView的每一個代理訪問。該屬性可以被每一個獨立的代理對象來決定當前選擇的是哪一個條目:


        在這種情況下,附加類型的名稱是ListView和屬性isCurrentItem,附加屬性使用ListView.isCurrentItem引用。

        附加的signal handler也可以使用這種方式引用。例如:附加的signal handler是Component.isCompleted,當組件的建立過程完成後可以被用來執行一些JavaScript代碼。在下面的樣本中,一旦ListModel被完全建立,Component.onCompleted signal handler就會被自動執行:


         附加的類型名是Component以及completed訊號,附加的signal handler可以這樣引用:Component.isCompleted。

 【訪問附加屬性和Signal Handler的注意點】

        一個常見的錯誤是將設附加的屬性和signal handler可以直接從子物件中訪問。這並不是問題。附加類型的執行個體僅僅添加到特定的對象上,而不是對象以及其所有子物件之上。

       例如:下面的樣本是之前的附加屬性的改編版樣本。在這次中,代理是一個Item,Rectangle就是該Item的子物件:


        這並不像預期中那樣工作,因為ListView.isCurrentItem僅僅是附加到根代理對象,而不是它的子物件。由於Rectangle是代理的子物件,而不是代理本身,他不能使用ListView.isCurrentItem訪問isCurrentItem附加屬性。因此,rectangle必須通過根代理對象訪問isCurrentItem屬性:


         現在就可以通過 delegateItem.ListView.isCurrentItem正確引用到代理的isCurrentItem附加屬性。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.