本篇博客通過一個詳細的UI例子來逐個點介紹Qt Quick的基本用法,儘量通過簡單例子來覆蓋全部主要知識點,閱讀時請對照代碼來逐個理解各個知識點
Qt Quick基本用法
- Demo使用技巧:由於以下代碼集中了大量知識點,同時顯示會特別混亂,大家只要通過visible: false隱藏無關元素即可
- 註釋:Qml和Javascript一樣,通過雙斜槓添加註釋
- 給元素設置id:每個節點都可以設置一個id屬性,其它元素可能通過id關聯這個節點,參照node01
- 向DOM樹中添加節點:參照node02
- 導入類庫:Window,Text等元素都來自Qt Quick類庫,需要導入後才能使用,參照首行import語句
- Qml基本類型:Qml提供了int,real,string,bool,list等類型,不需要導入任何類庫就能使用
- Qt Quick內置類型:Qt Quick提供了date,point,rect,size,基本控件等類型,導入Qt Quick模塊即可使用
- Javascript類型:Qml可以像Javascript一樣,直接通過var來聲明一個對象,它沒有具體類名,但可以通過變量名直接訪問,參照node03和node04,node03聲明瞭一個innerObject對象,node04可以直接引用這個對象的值
- 執行Javascript代碼:在onCompleted,onClicked等方法內,可以執行Javascript代碼,參照node04
- 屬性引用:一個元素,可以直接使用其它元素的屬性值,或拿來進行運算,這個功能非常強大,比如我們想要高爲寬的一半時,只需寫出【height: width * 0.5】即可
- 通過錨佈局定位元素:錨佈局允許通過錨點,邊距,填充,居中等方式組合來定位元素位置,參照node05
- 設置元素點擊區域:通過給元素添加MouseArea子節點,可以爲元素添加點擊事件,並且可以控制點擊區域範圍,參照node06
- 設置字體:通過給Text元素添加font子節點,就可以設置Text的字體,當font的屬性很簡單隻有一個的時候,也可以簡寫成【font.bold: true】這種格式,參照node07
- 設置邊框:邊框的使用和字體同理,參照node08
- 圖片控件:通過Image元素可以顯示圖片,參照node09
- 設置鼠標滑入滑出事件:給MouseArea設置onEntered,onExited事件方法即可,參照node10
- 自定義組件:由於篇幅較長,稍後我們開一篇專門的博客來講解
- 編碼規範:由於一個Qml文件中可能包含諸多內容,爲了方便閱讀,應當有一個書寫規範,一般按照id,自定義屬性,屬性賦值,事件聲明,狀態聲明,動畫聲明,自定義函數的順序來編寫
- 定義動畫:Qt內置了AnchorAnimation,ColorAnimation,NumberAnimation,PathAnimation,PropertyAnimation,RotationAnimation等常用動畫,非常前面,如node11所示,是一個簡單的顏色漸變動畫
- 定義複雜動畫:上面介紹的是一個非常簡單的動畫,控件一創建便執行,實際大多情景比這個要複雜,動畫改變的屬性可能不止一個,動畫往往需要指定在狀態變化時執行,這時單純的Animation已經不再能滿足我們的需求,我們需要配合State和Transition來實現這些複雜動畫,參照node12
- 數組簡寫:在Qml中數組通過[ ]來表示,但是當數組只有一個元素時,也可以省略[ ]
- 加載Javascript代碼:Qml可以直接將Javascript加載爲一個模塊對象,直接進行使用,在這一點上,Qt Quick做得比原生Javascript更加先進,參照node13和import語句
- 可視基類:所有的Qt Quick可視化元素,即控件節點,都繼承自Item,參照node14,像x,y,z,width,height這些基本屬性,都是繼承自Item的
- 控件堆疊順序:當一個元素中包含多個子元素時,可以通過z值來控制元素的顯示順序,z值較大的將顯示在上面,遮擋z值較小的元素,默認的z值爲0,z值相同的情況下,排在佈局靠後的元素顯示在上層,參照node14
- 座標轉換:同一個點相對於不同控件的座標是不同的,比如對於一個Window-Item-Rectangle的三級Dom結構,點相對於Window,Item,Rectangle的座標都是不一樣的,除非這三級節點的左上角都是對齊的,要獲取一個點相對於某個元素的座標位置,可以參考node15
- 界面佈局:內容不難,但由於佈局有很多種,還有新版舊版之分,篇幅較長,接着我們開一篇專門博客來講解
- 顯示富文本:Text可以顯示覆雜帶樣式的文本,如加粗,傾斜,彩色,鏈接,序號等,通過【textFormat: Text.StyledText】或【textFormat: Text.RichText】即可啓用對應的功能,StyledText僅支持基本的簡單文本標籤,RichText支持HTML4標籤
- 使用文本編輯框:TextInput是一個文本編輯控件,但是它沒有任何默認樣式,甚至連基本的邊框都沒有,需要用戶自己定義,參照node16
- 更多高級控件和屬性:Qt每個控件都包含了諸多屬性,每一個都可以寫成一幅長篇博客,但是不管對於新手還是老手來說,這都不是一個明智之舉,這裏只講解核心知識點和思路,以便大家可以快速上手進行Qt項目開發,具體細節可以用到時再探究,死背屬性意義不大,以後換一種語言,換一種框架,可能又是新的屬性和用法,沒太大複用價值
Demo源碼
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import "script/math.js" as MathScript
//窗口節點
Window {
id: node01
visible: true
width: 640
height: 480
title: "Qt Quick Demo"
//測試基本使用
Text {
id: node02
visible: false
text: "Node 02"
}
//測試Javascript對象
Text {
property var innerObject: ({
"title": "Node 04"
})
id: node03
visible: false
text: "Node 03"
}
//測試Javascript代碼
Text {
id: node04
visible: false
text: node03.innerObject.title
Component.onCompleted: {
var jsObject = {
"id": 1,
"name": "Javascript Object"
}
console.log(node03.text)
console.log(node04.text)
console.log(jsObject.name)
}
}
//使用矩形區域測試錨佈局
Rectangle {
id: node05
visible: false
width: 400
height: 400
radius: 5
color: "red"
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: 10
anchors.topMargin: 10
}
//測試點擊區域
Rectangle {
id: node06
visible: false
width: 400
height: 400
color: "red"
anchors.centerIn: parent
//只能點擊下半區域
MouseArea {
anchors.fill: parent
anchors.topMargin: parent.height * 0.5
onClicked: {
console.debug("Rectangle Clicked")
}
}
}
//測試字體
Text {
id: node07
visible: false
text: "Node 07"
font {
pointSize: 30
bold: true
italic: true
}
}
//測試邊框
Rectangle {
id: node08
visible: false
width: 200
height: 200
color: "yellow"
border {
color: "red"
width: 2
}
}
//測試圖片
Image {
id: node09
visible: false
source: "images/1.png"
width: parent.width
height: parent.height
fillMode: Image.Stretch
}
//測試鼠標懸浮事件
Rectangle {
id: node10
visible: false
width: 200
height: width
color: "yellow"
radius: 100
border.color: "red"
border.width: 2
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
parent.border.width = 4
}
onExited: {
parent.border.width = 2
}
}
}
//測試基本動畫
Rectangle {
id: node11
visible: false
width: 200
height: width
radius: 100
//控件創建時,執行一個顏色漸變動畫
ColorAnimation on color {
from: "yellow"
to: "orange"
duration: 3000
}
}
//測試複雜動畫
Rectangle {
id: node12
visible: false
width: 200
height: width
radius: 100
state: "A"
//點擊時切換到狀態B
MouseArea {
anchors.fill: parent
onClicked: {
node12.state = "B"
}
}
//聲明兩種狀態,指定狀態值
states: [
State {
name: "A"
PropertyChanges {
target: node12
color: "yellow"
}
PropertyChanges {
target: node12.border
width: 2
color: "green"
}
},
State {
name: "B"
PropertyChanges {
target: node12
color: "orange"
}
PropertyChanges {
target: node12.border
width: 5
color: "blue"
}
}
]
//定義從A狀態切換到B狀態時的動畫
transitions: Transition {
from: "A"
to: "B"
ColorAnimation {
target: node12
duration: 3000
}
NumberAnimation {
target: node12.border
property: "width"
duration: 3000
}
}
}
//測試加載Javascript文件
Rectangle {
id: node13
visible: false
width: 200
height: width
radius: 100
color: "yellow"
Component.onCompleted: {
console.debug("MathScript", MathScript.sum(1, 1))
}
}
//測試Item
Item {
id: node14
visible: false
anchors.fill: parent
Rectangle {
width: 100
height: 100
x: 100
y: 100
z: 1
color: "red"
}
Rectangle {
width: 100
height: 100
x: 150
y: 150
z: -1
color: "lightblue"
}
}
//獲取控件座標
Rectangle {
id: node15
visible: false
anchors.fill: parent
color: "yellow"
Rectangle {
id: node15Rect
width: 100
height: 100
color: "red"
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: 10
anchors.leftMargin: 10
Component.onCompleted: {
//將node15Rect中的點,轉化爲在node15中的座標
console.debug(node15.mapFromItem(node15Rect, 0, 0))
//將node15中的點,轉化爲在node15Rect中的座標
console.debug(node15.mapToItem(node15Rect, 10, 10))
//同理,可將Item中的座標與Window中的座標進行轉換
//由於Window不繼承自Item,需要通過Window.contentItem來獲得根節點
console.debug(node01.contentItem.mapFromItem(node15Rect, 0, 0))
console.debug(node01.contentItem.mapToItem(node15Rect, 10, 10))
}
}
}
//測試文本編輯框
Rectangle {
id: node16
visible: true
anchors.fill: parent
anchors.margins: 100
color: "yellow"
TextInput {
id: node16Input
anchors.fill: parent
text: "Hello World"
color: "red"
font.pointSize: 50
focus: true
clip: true //文本裁剪,可以防止文本超出parent顯示
}
}
}
//math.js
function sum (a, b) {
return a + b;
}