Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Qt on Android:QML 語言基礎

Qt on Android:QML 語言基礎

編輯:關於Android編程

在《Qt on Android:Qt Quick 簡介》中我們提到 QML 語法和 Json 類似,請參考《Qt on Android: http下載與Json解析》查看 Json 語法。當然這裡我們是期望從零開始也能學會 QML ,所以呢,你也可以直接往下看。

對象

QML 文件的後綴是 qml ,其實就是個文本文件。下面是 一個簡單的 QML 文件:

import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import an.qt.ImageProcessor 1.0
import QtQuick.Controls.Styles 1.1

Rectangle {
    width: 320;
    height: 480;
    color: "#121212";
    
    Image {
        source: "images/IMG_001.jpg";
        anchors.centerIn: parent;
    }
}

這個簡單的 QML 文件的開始是 import 語句,如 import QtQuick 2.0 這句,會引入 QtQuick 2.0 模塊,哇,真是廢話!接著廢話吧。 import 和 C++ 中的 #include 類似,與 Java 中的 import 效果一樣,與 JavaScript 中的……唐僧了,打住。

Rectangle{ } 語句,定義了一個類型為 Rectangle 的對象。如果你看了《Qt on Android: http下載與Json解析》一文中有關 Json 的語法描述,應該已經知道對象要用一對花括號來描述。沒錯, QML 裡也是這樣,不過呢,花括號前要寫上對象的類型。就這麼簡單!

示例 QML 文檔中有兩個對象,一個是 Rectangle ,一個是 Image 。

在花括號之間,是對象的屬性描述(還可以有其它的,後面再說),屬性是以 "property: value" 形式指定的,這點和 Json 一樣。如你所見, Rectangle 對象有 width 、 color 等屬性。

屬性可以分行書寫,此時語句後可以不要 ";" 號,不過筆者建議 C++ 程序猿都加上 ";" ,這會避免你患上精神分裂症。當然,也可以把多個屬性寫在一行內,多個屬性之間必須以 ";" 分割。如下所示:

Rectangle {
    width: 320; height: 480; color: "#121212";
}
我強烈建議你不要這麼干!除非有代碼意外的原因,比如排版需要,比如老板覺得你代碼行數太多……

表達式

在《Qt on Android:Qt Quick 簡介》中筆者已經提到, QML 支持 JavaScript 表達式。比如你可以這樣改寫 Rectangle 對象的寬、高屬性:

Rectangle {
    width: 23*10; 
    height: 6*80; 
    color: "#121212";
}

我只是示意啊,你在實際項目中可別這麼寫,這種行為往不好聽裡說,有點兒腦殘……當然我也可以舉一個有意義的示例:

Button {
    text: "Quit";
    style: ButtonStyle {
        background: Rectangle {
            implicitWidth: 70;
            implicitHeight: 25;
            border.width: control.activeFocus ? 2 : 1;
        }
    }
}

在這個示例中我指定了按鈕風格中的背景矩形,在按鈕有焦點時邊框寬度為 2 沒有焦點時寬度為 1 。語句 "border.width: control.activeFocus ? 2 : 1" 使用了 JavaScript 的 "?:" 三元雲算法( C++ 中貌似也有……)。

另外,慧眼如你,可能已經注意到,上面的表達式中我使用了 "control.activeFocus" ,沒錯,在表達式中可以引用其它對象及其屬性。當你這麼做的時候,待賦值的屬性就和你所引用的對象的那個屬性建立了關聯,當被引用屬性發生變化時,表達式的值會重新計算,而待賦值的屬性也會變化。

也許你心中已經有了疑問:如何引用一個對象呢?答案是:通過對象的 id 值來引用一個對象。看這裡:

Rectangle {
    width: 320;
    height: 480;
    
    Button {
        id: openFile;
        text: "打開";
        anchors.left:  parent.left;
        anchors.leftMargin: 6;
        anchors.top: parent.top;
        anchors.topMargin: 6;
    }

    Button {
        id: quit;
        text: "退出";
        anchors.left: openFile.right;
        anchors.leftMargin: 4;
        anchors.bottom: openFile.bottom;
    }
}


上面的示例中,退出按鈕使用 id( openFile )引用了打開按鈕。

我的乖呀,anchors 是什麼東東……先別管它,下一篇會講到。

注釋

在 QML 中,注釋與 C++ 中一樣,單行以 "//" 開始,多行以 "/*" 開始以 "*/" 結束。

注釋是不被執行的,添加注釋可對代碼進行解釋或者提高其可讀性。注釋同樣還可用於防止代碼執行,這對跟蹤問題是非常有用的。

使用注釋的示例 QML :

/*
 * the root element of QML
 */
Rectangle {
    width: 320;
    height: 480;
    
    Button {
        id: quit;
        text: "退出";
        //use anchors to layout
        anchors.left: openFile.right;
        anchors.leftMargin: 4;
        anchors.bottom: openFile.bottom;
        //set z-order
        z: 1;
    }
}

屬性

其實, QML 中的屬性,就是我們非常熟悉的 C++ 中的成員變量……

屬性命名

屬性名的首字母一般以小寫開始,如我們看煩了的 width 屬性。

如果屬性名以多個單詞表示,那麼第二個及以後的單詞,首字母大寫。

屬性類型

可以在 QML 文檔中使用的類型大概有三類:

由 QML 語言本身提供的類型使用 QML 模塊注冊 C++ 類型由 QML 模塊提供的類型

我們先看 QML 語言提供的基本類型。

基本類型

QML 支持的基本類型包括整型、實數型、布爾、字符串、顏色、列表等等。這些基本類型有些是和 JavaScript 語言的基本類型對應的。

還是之前的示例,修改了一下,通過注釋標注了屬性類型:

Rectangle {
    width: 320; //int 
    height: 480;
    
    Button {
        id: quit;
        text: "退出"; //string
        anchors.left: openFile.right;
        anchors.leftMargin: 4;
        anchors.bottom: openFile.bottom;
        z: 1.5; // real
        visible: false; //bool
    }
}

注意, QML 中屬性是有類型安全檢測的,也就是說你只能指定與屬性類型匹配的值,否則會報錯。

請使用 Qt 助手的索引模式,以"qml basic types " 為關鍵字檢索,找到 QML Basic Types 頁面來查看完整的類型列表和每個類型的詳情。

Qt 的 QML 模塊還未 QML 引入的很多 Qt 相關的類型,如 Qt 、 QtObject 、Component 、 Connections 、 Binding 等,請使用 Qt 助手檢索 "qt qml qml types" 來了解。

id 屬性

之前在介紹表達式時提到了 id 屬性,這裡展開描述一下。

一個對象的 id 屬性是唯一的,在同一個 QML 文件中不同對象的 id 屬性的值不能重復。當給一個對象指定了 id ,就可以在其它對象或腳本中通過 id 來引用該對象。在“表達式”一節中我們已經演示了如何通過 id 來引用一個對象。

請注意, id 屬性的值,首字符必須是小寫字母或下劃線並且不能包含字母、數字、下劃線以外的字符。

列表屬性

列表屬性類似於下面這樣:

Item {
    children:[
        Image{},
        Text{}
    ]
}

列表是包含在方括號內,以逗號分隔的列表元素。看起來是不是挺熟悉?在《Qt on Android: http下載與Json解析》中,我們舉過 Json 數組的例子,再看看:

[
  "name":"zhangsan", 
  {
    "age":30,
    "phone":"13588888888",
    "other": ["xian", null, 1.0, 28]
  }
]

其實列表和 JavaScript 的數組是類似的,其訪問方式也一樣:

length 屬性提供了列表內元素的個數列表內的元素通過數組下標來訪問([index])

值得注意的是,列表內只能包含 QML 對象,不能包含任何基本類型(如整型、布爾型)。這點與 Json 是不一樣的。下面是訪問列表的示例:

Item {
    children:[
        Text{
            text: "textOne";
        },
        Text{
            text: "textTwo";
        }
    ]
    Component.onCompleted:{        
        for (var i = 0; i < children.length; i++)
            console.log("text of label ", i, " : ", children[i].text)
    }
}

如果你一個列表內只有一個元素,也可以省略方括號。如下所示:

Item {
    children:Image{}
}


不過筆者還是建議你始終使用方括號,哪怕其中只有一個元素。

有沒有什麼問題?有就要說啊,悶在心裡會憋壞自己的。好吧,你不說我就說了。在我們訪問列表的示例中出現了一個新的內容,Component.onCompleted :{} ,這是什麼東東呢?接下來我們就來講它。

信號處理器

信號處理器,其實等價於 Qt 中的槽。但是我們沒有看到類似 C++ 中的明確定義的函數……沒錯,就是這樣,你的的確確只看到了一對花括號!對啦,這是 JavaScript 中的代碼塊。其實呢,你可以理解為它是一個匿名函數。而 JavaScript 中的函數,其實具名的代碼塊。函數的好處是你可以在其它地方根據名字調用它,而代碼塊的好處是,除了定義它的地方,沒人能調用它,一句話,它是私有的。代碼塊就是一系列語句的組合,它的作用就是使語句序列一起執行。

讓我們回頭再看信號處理器,它的名字還有點兒特別,一般是 on{Signal} 這種形式。比如 Qt Quick 中的 Button 元素有一個信號 clicked() ,那麼你要可能會寫出這樣的代碼:

Rectangle {
    width: 320;
    height: 480;
    
    Button {
        id: quit;
        text: "退出";
        anchors.left: parent.left;
        anchors.leftMargin: 4;
        anchors.bottom: parent.bottom;
        anchors.bottomMargin: 4;
        onClicked: {
            Qt.quit();
        }
    }
}

上面的 QML 代碼其實已經是一個簡單 QML 應用了,這個應用在窗口的左下角放了個退出按鈕,當用戶點擊它時會觸發按鈕的 clicked() 信號,而我們定義了信號處理器來響應 clicked() 信號——調用 Qt.quit() 退出應用。

你看到了,當信號是 clicked() 時,信號處理器就命名為 onClicked 。就這麼簡單,以 on 起始後跟信號名字(第一個字母大寫)。

分組屬性

在某些情況下使用一個 '.' 符號或分組符號把相關的屬性形成一個邏輯組。分組屬性可寫以下這樣:

Text {
    font.pixelSize: 18;
    font.bold: true;
}

也可以這樣寫:

Text {
    font { pixelSize: 12; bold: true; }
}

其實呢,可以這麼理解,font 屬性的類型本身是一個對象,這個對象又有 pixelSize / bold / italic / underline 等等屬性。對於類型為對象的屬性值,可以使用 "." 操作符展開對象的每一個成員對其賦值,也可以通過分組符號(一對花括號)把要賦值的成員放在一起給它們賦值。對於後者,其形式就和對象的定義一樣了,起碼看起來木有區別。所以呢,又可以這麼理解上面的示例: Text 對象內聚合了 font 對象。 OK ,就是聚合。

附加屬性

屬性真難搞!到現在還沒講完,不但你煩了,我也快坐不住了。我保證,這是最後一個要點了,不過也是最復雜最難以理解的屬性了。對於這種玩意兒,我一向的做法時,不能理解的話就接受,你就當它生來如此,存在即合理,只要學會怎麼用它就 OK 了。

在 QML 語言的語法中,有一個附加屬性(attached properties)和附加信號處理器(attached signal handlers)的概念,這是附加到一個對象上的額外的屬性。從本質上講,這些屬性是由附加類型(attaching type)來實現和提供的,它們可能被附加到另一種類型的對象上。附加屬性與普通屬性的區別在於,對象的普通屬性是由對象本身或其基類(或沿繼承層級向上追溯的祖先們)提供的。

舉個例子,下面的 Item 對象使用了附加屬性和附加信號處理器:

import QtQuick 2.0

Item {
    width: 100; 
    height: 100;

    focus: true;
    Keys.enabled: false;
    Keys.onReturnPressed: console.log("Return key was pressed");
}

你看, Item 對象可以訪問和設置 Keys.enabled 和 Keys.onReturnPressed 的值。 enabled 是 Keys 對象的一個屬性。 onReturnPressed 其實是 Keys 對象的一個信號。對於附加信號處理器,和前面講到的普通信號處理器又有所不同。普通信號處理器,你先要知道信號名字,然後按照 on{Signal} 的語法來定義信號處理器的名字;而附加信號處理器,你只要通過附加類型名字引用它,把代碼塊賦值給它即可。

最後說下 Keys 對象,它是 Qt Quick 提供的,專門供 Item 處理按鍵事件的對象。它定義了很多針對特定按鍵的信號,比如上面的 onReturnPressed ,還定義了更為普通的 onPressed 和 onReleased 信號,一般地,你可以使用這兩個信號來處理按鍵(請對照 Qt C++ 中的 keyPressEvent 和 keyReleaseEvent 來理解)。它們有一個名字是 event 的 KeyEvent 參數,包含了按鍵的詳細信息。如果一個按鍵被處理, event.accepted 應該被設置為 true 以免它被繼續傳遞。

下面是使用 onPressed 信號的一個示例,它檢測了左方向鍵:

Item {
    anchors.fill: parent;
    focus: true;
    Keys.onPressed: {
        if (event.key == Qt.Key_Left) {
            console.log("move left");
            event.accepted = true;
        }
    }
}


好啦,關於 QML 語言的基礎性介紹就到這裡,相信現在你已經可以看懂簡單的 QML 文檔了。有的同學可能又疑問了,這節還有一些東東只見用不見講啊,比如 Rectangle / Text / Image / Item / Button / Component / Qt 等等,抱歉,現在只能揣著糊塗裝明白了,下一篇我們會講這些東西。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved