QML語法
1.QML基本語法
1.1導入聲明
導入聲明允許客戶端告訴QML引擎可以在QML文檔中使用哪些模塊,JavaScript資源以及組件目錄。文檔中可以使用的類型依賴於在文檔中導入的模塊、資源以及目錄。
導入類型
總共有三種類型的導入。對於每一種導入類型在語法上都有細微的差別,並且不同的導入類型有着不同的語義。
*模塊(命名空間)的導入
最常用的導入類型就是模塊導入。客戶端可以導入那些已經注冊QML對象類型和JavaScript資源到給定命名空間的QML模塊。
導入模塊最通用的格式如下:
a) <ModuleIdentifier>使用URI格式指定,用於唯一標示該模塊提供的類型命名空間
b) <Version.Number>是以如下格式MajorVersion.MinorVersion標示模塊版本號的
c) <Qualifier>是一個可選的,本地命名空間標示符。模塊的對象類型和JavaScript資源都安裝到這個命名空間中。如果沒有指 定,那么該模塊的對象類型和JavaScript資源則安裝到了全局的命名空間。
一個沒有使用限定語的模塊導入聲明如下:
這個導入示例允許使用者使用QtQuick模塊提供的所有類型而不用指定限定詞。例如,客戶端可以如下創建一個矩形區域:
一個使用了限定詞的導入聲明的示例如下:
注意:如果一個QML文檔使用了模塊並未導入的對象類型,那么將會產生錯誤。例如,下面的文檔沒有導入QtQuick但是卻試圖使用Rectangle類型:
在這種情況下,QML引擎將會觸發一個錯誤,並且拒絕加載該QML文件。
【非模塊命名空間的導入】
類型可以直接通過C++中的多種注冊方法(例如qmlRegisterType())注冊到命名空間中。如果類型通過這種方式注冊到命名空間中,而且該命名空間又是模塊的標示符,那么我們可以通過導入該命名空間來導入該類型。
【 導入到一個本地限定的命名空間】
導入聲明可選的使用as關鍵詞將類型導入至指定的文檔范圍有效的本地命名空間中。如果指定了一個命名空間,那么之后使用 這些類型就必須加上這個限定詞作為前綴。
在下面,QtQuick模塊被導入到命名空間”CoreItems”。現在,任何引用QtQuick模塊中的類型必須加上CoreItems名稱前綴:
一個命名空間就像是一個模塊在文件內的標示符。命名空間不能成為根對象的屬性,根對象可以使用屬性、信號和方法。
命名空間導入對於在兩個不同模塊提供了相同名稱的QML對象的情況下十分有效。在這種情況下我們可以將兩個模塊導入兩個不同的本地命名空間中,以此來確保代碼可以引用到需要的類型。
注意:多個模塊可以導入到同一個命名空間中,同理多個模塊可以導入到全局命名空間中。例如:
*目錄的導入
我們可以導入包含QML文檔的目錄到QML文檔中。這提供一種重用QML類型的方式:文件系統上的目錄
導入目錄的一般形式如下:
注意:導入的路徑是網絡可傳輸的:應用程序可以像導入本地路徑那樣導入遠端路徑。可以查看QML文檔網絡傳輸一節中URL解析的規則。如果導入的是遠端的 目錄,那么那么它必須包含一個目錄導入列表文件,因為如果qmldir文件不存在,那么QML引擎就不能識別出遠端目錄中的內容。
至於<Qualifier>的語義跟前面介紹的一樣。關於這種類型的導入,更新信息請見“目錄導入”。
【目錄導入】
一個包含QML文件的本地目錄可以無需任何額外配置直接導入。一個包含QML文件的遠端目錄也可以被導入,但是需要一個目錄列表qmldir文件存在。 一個本地目錄也可以有一個可選的目錄列表qmldir文件用以定義那些必須導入給客戶端的類型名稱以及指定那些必須導入給客戶端的JavaScript資 源。
【本地目錄導入】
任何本地文件系統上的QML文件都可以使用導入聲明以及目錄的絕對或者相對路徑導入本地目錄,使得QML文件可以使用定義在該目錄中的對象系統。
如果本地目錄包含一個目錄列表qmldir文件,那么可以使用qmldir文件中指定的對象類型,否則就會使用來自QML文檔文件名作為類型名。如果目錄 中沒有qmldir文件,那么僅僅那些文件名以大寫字母開頭,以”.qml”結尾的文件名會作為對象類型。
示例:
考慮如下的QML工程目錄結構。在頂層目錄myapp下,有一個用於存放公共UI組件的子目錄mycomponents,主要的程序代碼在子目錄main下:
Main/application.qml文件可以使用相對路徑導入mucomponents目錄,使得應用程序可以使用該目錄下的QML對象類型:
在導入該目錄的時候也可以指定一個限定詞:
導入本地路徑是十分方便的,但是當目錄的位置發生變化,那么我們不得不更新應用程序中的導入聲明。但是這也可以通過QML模塊來避免,因為一個安裝的模塊用一個唯一確定的字符串就可以導入,而不需要文件系統路徑。
【遠端目錄導入】
如果遠端目錄包含一個目錄列表qmldir文件,那么QML文件也可以導入遠端目錄。
例如,如果之前的應用程序myapp目錄存放在”http://www.my-example-server.com”,mycomponents目錄包含如下定義的qmldir文件:
接着,我們就可以使用URL來導入mycomponents遠端目錄了:
注意:當導入一個遠端目錄,我們僅僅可以訪問qmldir文件中聲明的QML和JavaScript文件。
警告:當導入遠端目錄時,開發者必須十分小心僅僅加載那些信任的資源而應該避免加載非法代碼。
【目錄列表qmldir文件】
目錄列表文件qmldir區別於模塊定義qmldir文件。目錄列表qmldir文件允許一組QML文檔快速簡單的共享,但是它並不定義類型命名空間到文檔中,它也不支持QML對象類型版本。
目錄列表qmldir文件語法如下:
上面兩行的區別在於:沒有internal的代表導入該目錄的QML文檔可使用該對象類型;而包含internal則代表這部分的對象類型為內部的,不能供客戶端使用。
一個本地目錄可選的包含qmldir文件。這允許引擎僅僅暴露明確羅列在qmldir文件中的對象類型和JavaScript資源給客戶端。
[導入目錄示例]( qtdeclarative\examples\quick\tutorials\gettingStartedQml)
*JavaScript資源的導入
JavaScript資源可以在QML文檔中直接導入。每一個JavaScript資源都必須有一個標示符用以標示對該資源的引用。
通用的JavaScript資源導入聲明如下:
注意:這里的<Identifier>必須在文檔中是唯一的,而不能像本地命名空間那樣可以應用在多個模塊的導入。
模塊中的JavaScript資源
模塊可以提供JavaScript文件,通過添加JavaScript資源標示符到標示模塊的qmldir文件中 。
例如,如果projects.MyQMLProject.MyFunctions模塊使用如下qmldir文件指定,並且安裝到了QML導入路徑之中:
那么一個應用程序就可以通過導入該模塊來導入JavaScript資源,並且使用JavaScript資源的標示符來引用JavaScript資源:
如果該模塊被導入到本地的命名空間中,那么在JavaScript資源標示符之前還要加上本地命名空間的限定詞才可以引用JavaScript資源,如下所示:
更多信息
關於JavaScript資源的更多信息,可以參見文檔在QML中定義JavaScript資源,對如何導入JavaScript資源以及如何在JavaScript資源中使用導入,則可以參見文檔在QML中導入JavaScript資源。
[JavaScript資源導入示例]( qtdeclarative\examples\quick\demos\photoviewer)
QML導入路徑
當已安裝的模塊被導入,QML引擎就會在導入路徑中搜尋匹配的模塊。
導入路徑可以使用QQmlEngine::importPathList()方法獲取,定義了引擎默認搜索的路徑。默認情況下包含:
² 當前文件所在目錄
² 由QLibraryInfo::Qml2ImportsPath指定的路徑
² 由環境變量QML2_IMPORT_PATH指定的路徑
我們可以通過QQmlEngine::addImportPath()或者是環境變量QML2_IMPORT_PATH添加導入路徑。當執行qmlscene工具的時候,你也可以使用-I選項添加導入路徑。
調試
在尋找以及加載模塊出錯的時候QML_IMPORT_TRACE環境變量就十分有用。可以查看模塊導入調試獲取更多的信息。
【小結】
QML是一種聲明語言,允許定義對象和對象的屬性,以及它們是如何和其它對象交互的。與原生代碼相比較,在原生代碼中屬性和狀態的改變都是經過一系列的處理傳遞的,但是聲明性的QML語言直接在獨立的對象中集成了屬性和狀態的改變。
QML源代碼一般都是通過QML文檔由QML引擎加載的,QML引擎和QML代碼是分離的。這就允許我們定義可重用的QML對象類型。
一個QML文檔的開始部分可能有一個或多個導入聲明。一個導入聲明可能是以下幾種情況之一:
*一個帶有版本號的命名空間,對象都注冊到該命名空間中(例如:插件)
*一個包含了QML文檔定義類型的相關目錄
*一個JavaScript文檔
注意:JavaScript文檔導入的時候必須制定限定詞,這樣我們就可以引用它所提供的屬性和方法。
一般的導入類型如下:
例如:
1.2對象聲明
一個QML代碼塊定義了將被創建的QML對象樹。對象都是使用對象聲明定義的,對象聲明描述了對象的類型以及賦予該對象的屬性。每一個對象都可以使用嵌套的聲明語法定義子對象。
一個簡單對象的聲明如下:
上例中聲明了一個Rectangle類型的對象,之后跟着一對括號包圍了該對象的屬性。Rectangle對象是QtQuick模塊提供的,這里定義的三個屬性也都是rectangle的width,height和color屬性。
如果上述對象的聲明是QML文檔的一部分,那么它就可以被QML引擎加載。不過該文檔必須導入QtQuick模塊:
將上述內容存入.qml文件並使用QML引擎加載,則效果如下:
注意:如果定義的對象只有少數幾個屬性,那么就可以像這樣寫在一行,各個屬性之間用分號分隔:
顯然,在這個例子中定義的Rectangle對象十分簡單,只是僅僅定義了它的幾個屬性值。要創建更加有用的對象,一個對象也許就有許多的屬性:這個在QML對象屬性文檔中描述。另外,一個對象也可能包含子對象,我們下面就來討論這種情況。
1.2.1子對象
任何對象都可以通過嵌套對象聲明子對象。在這種情況下,任何對象的聲明都隱式的聲明了一個可能包含任意數目子對象的對象樹。
例如,一個Rectangle對象的聲明可以包含一個Gradient對象的聲明,而Gradient對象又包含了兩個GradientStop對象的聲明:
當這個代碼被QML引擎加載時,QML引擎就會創建一個以Rectangle為根對象的對象樹;該根對象有一個Gradient子對象,該子對象又包含兩個GradientStop子對象。
注意:在QML對象樹的上下文中是父-子關系的對象在可視化場景的上下文中不是父-子關系。在可視化場景中的父-子關系是由QtQuick模塊提供的 Item類型表達的,Item類型是QML類型的基本類型,因為絕大多數的QML對象都會被渲染。例如:Rectangle和Text都是基於Item類 型的對象,在下面的例子中Text被作為Rectangle對象的可視化子對象聲明的:
在上述代碼中,如果Text對象引用它父親的值,那么它引用的就是它的可視化場景中的父親,而不是對象樹中的父親。在這個例子中,它們是相同的:此時 Rectangle既是Text在對象樹中的父對象也是Text在可視化場景中的父對象。然而,父親屬性是可以被修改的用以改變可視化場景中的父對象,而 我們是無法在QML中修改來修改對象樹上下文中的父對象。
另外,注意:Text對象並沒有作為Rectangle的一個屬性聲明,不像之前的例子中Gradient對象是指定為rectangle的gradient屬性。這是因為Item的孩子屬性直接設置為了該類型的默認屬性,這樣可以使得語法更簡單。
可以查看可視化父對象文檔獲取Item類型的關於可視化父對象更多概念信息。
1.3注釋
QML中的注釋和JavaScript中的注釋十分類似:
*單行的注釋是以//開始直到行尾結束;
*多行注釋是以/*開始,以*/結束
QML引擎在處理QML代碼的時候會忽略注釋信息。