QML 語言基礎


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

    版權全部 foruok,轉載請注明出處:http://blog.csdn.net/foruok

對象

   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 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; } } }


    在這個演示樣例中我指定了button風格中的背景矩形。在button有焦點時邊框寬度為 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;
    }
}


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

    我的乖呀,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 " 為keyword檢索。找到 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 應用了,這個應用在窗體的左下角放了個退出button。當用戶點擊它時會觸發button的 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;
        }
    }
}


    版權全部 foruok。轉載請注明出處:http://blog.csdn.net/foruok

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM