知識點:
自定義按鈕:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Button {
id:btn
x: 0
y: 62
text: "Quit2"
style:ButtonStyle {
background: Rectangle {
implicitWidth: 100
implicitHeight: 25
border.width: btn.pressed ? 2 : 1
}
}
}
}
多個窗口:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 1.4
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Button { // 會默認放到 data 列表中
id:btn
text: "Quit"
}
Window {
id: root2
visible: true
title: qsTr("Hello World")
width: 300
height: 100
flags: Qt.Popup
Text{
text: "Hello Qt Quick"
}
}
}
顏色 LinearGradient :
import QtQuick 2.12
import QtQuick.Window 2.12
import QtGraphicalEffects 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
width: 500
height: 500
border.color: Qt.lighter("purple")
border.width: 2
radius: 15
LinearGradient {
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(500, 500)
gradient: Gradient {
GradientStop {
position: 0.000
color: Qt.rgba(1, 0, 0, 1)
}
GradientStop {
position: 0.167
color: Qt.rgba(1, 1, 0, 1)
}
GradientStop {
position: 0.333
color: Qt.rgba(0, 1, 0, 1)
}
GradientStop {
position: 0.500
color: Qt.rgba(0, 1, 1, 1)
}
GradientStop {
position: 0.667
color: Qt.rgba(0, 0, 1, 1)
}
GradientStop {
position: 0.833
color: Qt.rgba(1, 0, 1, 1)
}
GradientStop {
position: 1.000
color: Qt.rgba(1, 0, 0, 1)
}
}
source: Image { source:"images/ufo.png" }
}
Component.onCompleted: {
console.log(color.r,color.g,color.b,color.a);
}
}
}

Text 控件 多余文字顯示 三個點:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtGraphicalEffects 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
color: "cyan"
Rectangle{
id:rect1
color: "purple"
width: 150
height: 100
Text {
id: txt1
anchors.fill:parent
text: qsTr("<h1>Hello Red Text,Hello Red Text,Hello Red Text,Hello Red Tex</h1>")
color:"red"
clip: true
wrapMode: Text.WrapAnywhere
elide: Text.ElideRight
}
}
}

Image 相關:
顯示GIF 圖片:
Image不能顯示GIF,因為Image只能顯示靜態圖片,可以使用 AnimatedImage 顯示動態圖片
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
color: "cyan"
Image {
id: img1
width: 100
height: 100
source: "images/1.gif" // 不能顯示GIF,因為Image只能顯示靜態圖片
}
// 可以使用 AnimatedImage 顯示動態圖片
AnimatedImage {
id:aniImg1
x:100
y:100
width: 100
height: 100
source: "images/1.gif"
}
}
異步加載網絡圖片:
使用了 BusyIndicator 組件
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
color: "cyan"
Rectangle{
width: 500
height: 500
border.color: "red"
border.width: 2
BusyIndicator{
id:loading
running: true
anchors.centerIn: parent
z:2 // z-index
}
Text {
id: desc
visible: false
anchors.centerIn: parent
z:3 // z-index
}
Image {
id: img1
cache: false // 在加載大型圖片一般不要進行緩存
anchors.fill: parent
source: "http://pic1.juimg.com/161122/330846-16112222051832-lp.jpg"
fillMode: Image.PreserveAspectFit
asynchronous: true // 開啟異步加載 圖片 網絡資源自動就是異步,本地資源默認都是同步
onStatusChanged: {
if(img1.status === Image.Loading){
loading.running = true;
desc.visible = false;
// console.log("loading");
}else if(img1.status === Image.Ready){
loading.running = false;
// console.log("ready");
}else if(img1.status === Image.Error){
loading.running = true;
desc.visible = true;
desc.text = "load img error";
// console.log("error");
}
}
// focus: true
// Keys.onPressed: {
// if(event.key === Qt.Key_A){
// console.log(img1.status,"|||| ",Image.Error);
// }
// }
}
}
}
效果:

圖片查看器(一次打開單張圖片):
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
minimumWidth: 480
minimumHeight: 360
BusyIndicator{
id:loading
running: false
anchors.centerIn: parent
z:2
}
Text {
id: stateTxt
visible: false
anchors.centerIn: parent
z:3
}
Image {
id: imageViewer
asynchronous: true // 異步加載
cache: false // 關閉緩存
anchors.fill: parent
fillMode: Image.PreserveAspectFit
onStatusChanged: {
if(imageViewer.status === Image.Loading){
loading.running = true;
stateTxt.visible = false;
}else if(imageViewer.status === Image.Ready){
loading.running = false;
}else if(imageViewer.status === Image.Error){
loading.running = true;
stateTxt.visible = true;
stateTxt.text = "load image error";
}
}
}
Button{
id:openFile
text: "Open"
anchors.left: parent.left
anchors.leftMargin: 8
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
onClicked:fileDialog.open()
}
FileDialog{
id:fileDialog
title: "Please choose a file"
nameFilters: ["Image Files (*.jpg *.png *.gif)"]
onAccepted: {
imageViewer.source = fileDialog.fileUrl;
var imageFile =new String(fileDialog.fileUrl);
imagePath.text = imageFile.slice(8);
}
}
Text {
id: imagePath
anchors.left: openFile.right
anchors.leftMargin: 8
anchors.verticalCenter: openFile.verticalCenter
font.pixelSize: 18
}
}

import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
minimumWidth: 480
minimumHeight: 360
BusyIndicator{
id:loading
running: false
anchors.centerIn: parent
z:2
}
Text {
id: stateTxt
visible: false
anchors.centerIn: parent
z:3
}
Image {
id: imageViewer
asynchronous: true // 異步加載
cache: false // 關閉緩存
anchors.fill: parent
fillMode: Image.PreserveAspectFit
onStatusChanged: {
if(imageViewer.status === Image.Loading){
loading.running = true;
stateTxt.visible = false;
}else if(imageViewer.status === Image.Ready){
loading.running = false;
}else if(imageViewer.status === Image.Error){
loading.running = true;
stateTxt.visible = true;
stateTxt.text = "load image error";
}
}
}
Button{
id:openFile
text: "Open"
anchors.left: parent.left
anchors.leftMargin: 8
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
onClicked:fileDialog.open()
}
FileDialog{
id:fileDialog
title: "Please choose a file"
nameFilters: ["Image Files (*.jpg *.png *.gif)","Bitmap Files (*.bmp)","* (*.*)"]
selectedNameFilter:"Image Files (*.jpg *.png *.gif)" // 默認過濾器
selectMultiple: true // 選擇多個文件
onAccepted: {
imageViewer.source = fileDialog.fileUrls[0];
var imageFile =new String(fileDialog.fileUrl[0]);
imagePath.text = imageFile.slice(8);
}
}
Text {
id: imagePath
anchors.left: openFile.right
anchors.leftMargin: 8
anchors.verticalCenter: openFile.verticalCenter
font.pixelSize: 18
}
}
Loader:
Loader 用來動態加載QML Component 組件,
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Loader{
id:redLoader
anchors.left: parent.left
anchors.leftMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
sourceComponent: colorComponent
onLoaded: {
item.color = "red"; // 這里的item 指的是 所加載的頂層對象即 rect
}
}
Component{
id:colorComponent // 注Component 中只能有一個id 屬性 和 一個頂層對象!!!
Rectangle{
id:rect
width: 50
height: 50
signal zcb(color clr)
MouseArea{
anchors.fill: parent
onPressed: rect.zcb(rect.color)
}
onZcb:{
rect.color = "yellow";
}
}
}
}
如果Loader加載的Item 想要處理按鍵事件,必須要把Loader 中的 focus 設置為true
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Loader{
id:redLoader
anchors.left: parent.left
anchors.leftMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
sourceComponent: colorComponent
onLoaded: {
item.color = "red";
}
// 如果Loader加載的Item 想要處理按鍵事件,必須要把Loader focus 設置為true,這樣它所加載的組件才可以接收到focus
focus: true // 開啟按鍵事件
}
Component{
id:colorComponent
Rectangle{
id:rect
width: 50
height: 50
signal zcb(color clr)
MouseArea{
anchors.fill: parent
onPressed: rect.zcb(rect.color)
}
onZcb:{
rect.color = "yellow";
}
focus: true
Keys.onPressed: {
console.log(event.key);
event.accepted = true;
}
}
}
}
從文件中加載組件:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Loader{
id:redLoader
anchors.left: parent.left
anchors.leftMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
// sourceComponent: colorComponent
source: "MyTest.qml"
onLoaded: {
console.log(item); //此時 item 仍然是頂層對象
item.color = "red";
}
// 如果Loader加載的Item 想要處理按鍵事件,必須要把Loader focus 設置為true,這樣它所加載的組件才可以接收到focus
focus: true // 開啟按鍵事件
}
}
import QtQuick 2.10
Rectangle{
id:colorComponent
width: 50
height: 50
signal zcb(color clr)
MouseArea{
anchors.fill: parent
onPressed: colorComponent.zcb(colorComponent.color)
}
onZcb:{
colorComponent.color = "yellow";
}
focus:true
Keys.onPressed: {
console.log(event.key);
event.accepted = true;
}
}
動態創建和銷毀控件:
利用Loader,可以通過設置source為 空串,設置sourceComponent 為undefined 可以銷毀控件 ~
在js 中動態創建組件對象:
有兩種方式:
1,使用Qt.createComponent() 動態創建一個組件對象,然后使用Component 的createObject() 創建它的實例對象。
2,使用Qt.createQmlObject() 從一個QML字符串直接創建一個實例對象
注:
如果已經有一個QML文件中定義了一個組件,你想創建它的實例對象,這時使用1較好。
如果QML對象本身是在運行時產生的,那么Qt.createQmlObject() 可能是比較好的選擇。
第一種,
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
anchors.fill: parent
focus: true
Keys.onPressed: {
if(event.key === Qt.Key_A){
// 創建組件對象
var newCom = Qt.createComponent("MyTest.qml");
newCom.createObject(rect,{"color":"cyan"});// 第一個參數為父級,后面是新創建組件的屬性
}
}
}
}
import QtQuick 2.10
Rectangle{
id:colorComponent
width: 50
height: 50
signal zcb(color clr)
MouseArea{
anchors.fill: parent
onPressed: colorComponent.zcb(colorComponent.color)
}
onZcb:{
colorComponent.color = "yellow";
}
focus:true
Keys.onPressed: {
console.log(event.key);
event.accepted = true;
}
}
第二種,
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
anchors.fill: parent
focus: true
Keys.onPressed: {
if(event.key === Qt.Key_A){
// 創建組件對象
var newCom = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20;}',
rect,
"newCom01"); // 第三個參數 是給對象關聯一個文件路徑,主要用於報告錯誤
}
}
}
}
銷毀動態創建的對象:
這里說的銷毀不是僅僅把對象的visible 設為false或者是opacity 設置為0 。
需要調用 destroy() 函數,
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.10
import QtQuick.Dialogs 1.3
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
anchors.fill: parent
property var mycom: null
focus: true
Keys.onPressed: {
if(event.key === Qt.Key_A){
// 創建組件對象
rect.mycom = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20;}',
rect,
"newCom01"); // 第三個參數 是給對象關聯一個文件路徑,主要用於報告錯誤
}
if(event.key === Qt.Key_B){
console.log(rect.mycom);
rect.mycom.destroy(0); // 0s 后銷毀
}
}
}
}
點擊a 創建,點擊b 銷毀~
Qt Quick 元素布局:
三大類:
1,前面說過的 錨布局(Anchor),它是利用Item 的anchors 屬性實現,非常方便!!!
2,定位器(Position),它包含了Row(行定位器),Column(列定位器),Grid(表格定位器),Flow(流定位器)
3,布局管理器(Layout),它包含 行布局(RowLayout),列布局(ColumnLayout),表格布局(GridLayout)
定位器Position
略
布局管理器Layout
Qml 的布局管理器和 Qt widgets 相似,它與定位器的不同之處在於:布局管理器會自動調整子Item 的尺寸來適應界面大小的變化。
要使用布局管理器,需要引入Layouts 模塊。
GridLayout:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rootItem
width: 360
height: 240
color:"#eee"
GridLayout{
width: 200
anchors.left: parent.left
anchors.leftMargin: 4
anchors.top: parent.top
anchors.topMargin: 4
rows:2
columns: 2
rowSpacing: 4
columnSpacing: 4
Rectangle{
id:rect1
width:100
height: 100
color: "purple"
Layout.columnSpan: 2
Layout.rowSpan: 2
Layout.fillWidth: true
}
Rectangle{
id:rect2
width:100
height: 100
color: "cyan"
}
Rectangle{
id:rect3
width:100
height: 100
color: "yellow"
}
}
}
}
RowLayout
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rootItem
width: 400
height: 240
color:"#eee"
RowLayout{
width: 400
anchors.left: parent.left
anchors.leftMargin: 4
anchors.top: parent.top
anchors.topMargin: 4
Rectangle{
id:rect1
width:100
height: 100
color: "purple"
}
Rectangle{
id:rect2
width:100
height: 100
color: "cyan"
}
Rectangle{
id:rect3
width:100
height: 100
color: "yellow"
Layout.fillWidth: true
}
}
}
}
ColumnLayout:
類似...
QML 常用控件:
1,行編輯:
TextInput ,TextField
2,文本塊:
TextEdit,TextArea
3,互斥分組:
ExclusiveGroup
4,RadioButton:
單選按鈕
5,CheckBox:
多選框
6,GroupBox:
分組框
7,ComboBox:
下拉框
8,ProgressBar:
進度條
9,TabView:
點擊標簽會進入對應界面,選項卡控件
10,Slider:
滑塊控件
11,Flickable:
Flickable提供一個較小的視窗來顯示一個較大的內容給用戶,並且用戶可以對改內容進行拖拽和輕拂
12,Screen:
它是顯示Item 的那個屏幕,它提供了一些只讀屬性來描述屏幕參數。
Canvas 畫布:
Canvas 是Item 的派生類,
1,畫布:
Canvas{
width: 300
height: 200
}
這即是一塊畫布,
2,畫師:
畫師是Context2D ,QT幫助文檔直接搜索Context2D ,
Canvas{
width: 300
height: 200
onPaint: {
var ctx = getContext("2d"); // 在QML 中,一塊畫布只有一個畫師
}
}
3,畫筆:
關於畫筆的屬性設置,在Contex2D對象 上都有,有筆的粗細(lineWidth),筆的顏色(strokeStyle)之類的
4,畫刷:
畫刷是用來填充畫筆勾勒出的區域的,屬性是fillStyle,
坐標系:
在2D世界,原點位於屏幕左上角(0,0), 向右是x 軸,向下是y軸。
圖元:
基本的圖元有線,弧,矩形,曲線,文本,圖片,
小試牛刀:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
onPaint: {
var ctx = getContext("2d"); // 在QML 中,一塊畫布只有一個畫師
ctx.lineWidth = 2;
ctx.strokeStyle = "red"; // 畫筆顏色
ctx.fillStyle = "blue"; // 畫刷 顏色
ctx.beginPath();
ctx.rect(60,50,120,80);
ctx.fill();
ctx.stroke(); // 使用stroke() 結束路徑的繪制
var gradient = ctx.createRadialGradient(200,140,40,280,220,20);
gradient.addColorStop(0.0,Qt.rgba(1,0,0,1.0));
gradient.addColorStop(1.0,Qt.rgba(0,0,1,1.0));
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.rect(200,140,80,80);
ctx.fill();
ctx.stroke();
}
}
}
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
onPaint: {
var ctx = getContext("2d"); // 在QML 中,一塊畫布只有一個畫師
ctx.lineWidth = 2;
ctx.strokeStyle = "red"; // 畫筆顏色
ctx.fillStyle = "blue"; // 畫刷 顏色
ctx.beginPath();
ctx.moveTo(100,80); // 移動到 100,80
ctx.lineTo(100,200); // 從當前位置到(x,y)點繪制一條直線
ctx.lineTo(300,200);
ctx.closePath(); // 結束當前的路徑,從路徑終點到起點繪制一條直線來封閉路徑
ctx.fill();
ctx.stroke(); // 使用stroke() 結束路徑的繪制
}
}
}
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
onPaint: {
var ctx = getContext("2d"); // 在QML 中,一塊畫布只有一個畫師
ctx.lineWidth = 2;
ctx.strokeStyle = "red"; // 畫筆顏色
ctx.fillStyle = "blue"; // 畫刷 顏色
ctx.font = "42px sans-serif";
ctx.beginPath();
ctx.moveTo(4,4);
ctx.bezierCurveTo(0,height - 1,width -1 ,height/2,width/4,height/4);
ctx.lineTo(width/2,height/4);
ctx.arc(width*5/8,height/4,width/8,Math.PI,0,false);
ctx.ellipse(width*11/16,height/4,width/8,height/4);
ctx.lineTo(width/2,height*7/8);
ctx.text("Hello World",width/4,height*7/8);
ctx.fill();
ctx.stroke(); // 使用stroke() 結束路徑的繪制
}
}
}
與文本相關:
有三個方法:fillText() ,strokeText(),text()
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
onPaint: {
var ctx = getContext("2d"); // 在QML 中,一塊畫布只有一個畫師
ctx.lineWidth = 2;
ctx.strokeStyle = "red"; // 畫筆顏色
ctx.font = "42px sans-serif";
ctx.fillStyle = "green"; // 畫刷顏色
//1
ctx.beginPath();
ctx.text("Hello World -fill",50,50);
ctx.fill();
//2
ctx.fillText("Hello World -fillText",50,150);
//3
ctx.beginPath();
ctx.text("Hello World -stroke",50,200);
ctx.stroke();
//4
ctx.strokeText("Hello World -strokeText",50,250);
//5
ctx.beginPath();
ctx.text("Hello World -fill -stroke",50,300);
ctx.fill();
ctx.stroke();
}
}
}

繪制圖片:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
property var imgSrc:"images/rocket.png"
onPaint: {
var ctx = getContext("2d");
//1
ctx.drawImage(imgSrc,100,100);
}
Component.onCompleted: loadImage(imgSrc); // loadImage 會異步加載圖片,當圖片加載完成時會發射imageLoaded 信號
onImageLoaded: {
requestPaint(); // 重新繪制 Canvas 畫布
}
}
}
變換:
平移(translate),旋轉(rotate),縮放(scale),錯切(shear),
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
property var imgSrc:"images/rocket.png"
onPaint: {
var ctx = getContext("2d");
ctx.lineWidth = 2;
ctx.strokeStyle = "blue";
ctx.fillStyle = "purple";
ctx.save();
ctx.beginPath();
ctx.translate(width/2,height/2);
ctx.arc(0,0,30,0,Math.PI*2);
ctx.arc(0,0,50,0,Math.PI*2);
ctx.arc(0,0,70,0,Math.PI*2);
ctx.arc(0,0,90,0,Math.PI*2);
ctx.stroke();
ctx.restore(); // 恢復到save() 之前的狀態
ctx.save();
ctx.translate(width/2,30);
ctx.font = "42px sans-serif";
ctx.textAlign="center";
ctx.fillText("concentric circles",0,0);
ctx.restore();
}
}
}
Note :restore() 和 save()結合使用,
裁剪:
Context2D 的clip() 方法,讓我們能夠根據當前路徑包圍的區域來裁剪。
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{
width: 800
height: 600
property var imgSrc:"images/1.jpg"
onPaint: {
var ctx = getContext("2d");
ctx.lineWidth = 2;
ctx.strokeStyle = "blue";
ctx.fillStyle = Qt.rgba(0.3,0.5,0.7,0.3);
ctx.save();
ctx.beginPath();
ctx.arc(180,150,80,0,Math.PI*2,true);
ctx.closePath();
ctx.clip(); // 裁剪
ctx.drawImage(imgSrc,0,0);
ctx.stroke();
ctx.fill();
ctx.rotate(Math.PI/5);
ctx.font = "italic bold 32px serif";
ctx.fillStyle = "red"; // 字體填充顏色
ctx.fillText("Hello World,Wosdfjklf ",100,70);
ctx.restore();
}
Component.onCompleted: loadImage(imgSrc);
onImageLoaded: requestPaint();
}
}

圖像合成:
globalCompositeOperation

QML 動畫:
基本動畫對象:
PropertyAnimation: 通過改變各種類型的property 來產生動畫
NumberAnimation: PropertyAnimation 的子類,專門改變數字類型的property來產生動畫,效率比PropertyAnimation 好,
ColorAnimaiton : PropertyAnimation 的子類,專門改變color 類型的property 來產生動畫,效率比PropertyAnimation 好,
RotationAnimaiton : PropertyAnimation 的子類,專門改變rotation 值來產生動畫,效率比PropertyAnimation 好,另外還提供旋轉方向等附加屬性,
Vector3dAnimation: PropertyAnimation 的子類,當一個Vector3d值 發生變化時使用。
PathAnimation: 讓對象沿一個給定的方向移動
SmoothedAnimation: 允許一個property 跟蹤一個值,產生平滑動畫
SpringAnimation, 允許一個property 跟蹤一個值,動畫效果類似於彈簧運動,
分組動畫對象:
SequentialAnimation: 順序執行一系列動畫
ParallAnimation : 並行執行一系列動畫
動畫搭檔:
State,它是Item的狀態,不同狀態對應不同的界面效果和業務邏輯。
Transition, 過渡,它用來銜接不同狀態,使狀態變化過程平滑。
協同動畫元素:
Behavior : 它為Item 的property 變化綁定一個默認的動畫對象。
ParentAnimation, 當改變一個Item的parent的時候使用,使得從舊parent到新parent的過程更平滑,通常與State,Transition,ParentChange聯合使用。
AnchorAnimation: 當改變一個Item 的 anchor的時候使用,通常與State,Transition,AnchorChange聯合使用。
PauseAnimation:如果在動畫過程插入它,可以將動畫過程暫停一段時間。
PropertyAction: 動畫執行過程立即改變某個屬性。
ScriptAction:動畫執行過程運行一段JS腳本。
測試代碼:
PropertyAnimation定義的三種方式:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 50
anchors.centerIn: parent
color: "blue"
MouseArea{
anchors.fill: parent
onClicked: animation.running = true;
}
}
Rectangle{
id:rect2
width: 50
height: 50
color: "red"
}
PropertyAnimation{
id:animation
targets: [rect,rect2]
properties: "width,height"
to:150
duration: 1000;
}
}
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 50
anchors.centerIn: parent
color: "blue"
MouseArea{
anchors.fill: parent
onClicked: PropertyAnimation{ // 在信號處理器中直接使用動畫
id:animation
target: rect
properties: "width,height"
to:150
duration: 1000;
}
}
}
}
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 50
anchors.centerIn: parent
color: "blue"
MouseArea{
id:mouseArea
anchors.fill: parent
}
PropertyAnimation on width{ // Animation on <property > 這種語法格式 可以將一個動畫和一個屬性關聯起來
to:150
duration: 1000
running: {
return mouseArea.pressed
}
}
}
}
Animation 的started() 和 stopped() 信號:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 150
anchors.centerIn: parent
color: "blue"
property var animation;
PropertyAnimation{
id:toSquare
target: rect
property: "width"
to:150
duration: 1000
onStarted: {
rect.animation = toSquare;
rect.color = "red";
}
onStopped: {
rect.color = "blue";
}
}
PropertyAnimation{
id:toRect
target: rect
property: "width"
to:50
duration: 1000
onStarted: {
rect.animation = toRect;
rect.color = "red";
}
onStopped: {
rect.color = "blue";
}
}
MouseArea{
id:mouseArea
anchors.fill: parent
onClicked: {
if(rect.animation == toRect || rect.animation == undefined){
toSquare.start();
}else{
toRect.start();
}
}
}
}
}
NumberAnimation:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 150
anchors.centerIn: parent
color: "blue"
NumberAnimation {
id:numAni
target: rect
property: "width"
to:150
duration: 200
easing.type: Easing.InOutQuad
}
MouseArea{
id:mouseArea
anchors.fill: parent
onClicked: {
numAni.running = true;
}
}
}
}
ColorAnimation:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 150
anchors.centerIn: parent
color: "blue"
MouseArea{
id:mouseArea
anchors.fill: parent
onClicked: ColorAnimation {
target: rect
property: "color"
to: "green"
duration: 200
}
}
}
}
RotationAnimation:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 50
height: 150
anchors.centerIn: parent
color: "blue"
// transformOrigin: Item.TopRight
Text {
id: txt
anchors.fill: parent
text: qsTr("text")
}
MouseArea{
id:mouseArea
anchors.fill: parent
onClicked: RotationAnimation{
target: rect
to:90
duration: 1000
direction: RotationAnimation.Clockwise // 順時針
}
}
}
}
PathAnimation:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Canvas{ // 畫一個半圓
width: 400
height: 240
onPaint: {
var ctx = getContext("2d");
ctx.lineWidth = 4;
ctx.strokeStyle = "red";
ctx.beginPath();
ctx.arc(200,0,160,Math.PI*2,0,false);
ctx.stroke();
}
}
Rectangle{
id:rect
width: 40
height: 40
color: "blue"
x:20
y:0
MouseArea{
id:mouseArea
anchors.fill:parent
onClicked: pathAnim.start();
}
PathAnimation{
id:pathAnim
target: rect
duration: 6000
anchorPoint: "20,20"// rect 的center
orientation: PathAnimation.BottomFirst
orientationEntryDuration: 200 // 調整初始姿態的時間
endRotation: 0 // 最后的角度 :0
orientationExitDuration: 200 // 調整終止時姿態的時間
easing.type: Easing.InOutCubic
path: Path{
startX: 40
startY: 0
PathArc{
x:360 // 終點(360,0)
y:0
useLargeArc: true; // 采用 優弧(較大)模式
radiusX: 160 // 橢圓的兩個半軸
radiusY: 160
direction: PathArc.Counterclockwise // 逆時針
}
}
}
}
}
SmoothedAnimation:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 40
height: 40
color: "red"
x:20
y:20
SmoothedAnimation{ // SmoothedAnimation默認采用 easing.type 為InOutQuad
id:smoothAni1
target: rect
property: "x"
duration: 1000
velocity: -1 //速率 默認速率是200units/秒, -1 為禁用速率
// 如果duration和 velocity同時設置,那么會使用速率計算出一個時間, 它和duration的較短者會被采用。
}
SmoothedAnimation{
id:smoothAni2
target: rect
property: "y"
velocity: 100
}
}
MouseArea{
anchors.fill: parent
onClicked: {
smoothAni1.from = rect.x;
smoothAni1.to = mouse.x + 4;
smoothAni1.start();
smoothAni2.from = rect.y;
smoothAni2.to = mouse.y + 4;
smoothAni2.start();
}
}
}
SpringAnimation:
可以用來模擬彈簧的震盪行為,
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 40
height: 40
color: "red"
x:20
y:20
}
SpringAnimation{
id:springAni1
target: rect
property: "x"
spring: 3 // 加速度 0-5 有意義 默認為0
damping: 0.06 //衰減系數0-1.0 有意義, 值越大會越快平復
epsilon: 0.25 //允許設定一個最接近0 的閾值代表0 ,如果是基於像素動畫,建議0.25 ,如果是基於scale動畫,建議0.005 。 默認為0.01 ,調整epsilon 可能會有一定的性能提升
}
SpringAnimation{
id:springAni2
target: rect
property: "y"
spring: 3
damping: 0.06
epsilon: 0.25
}
MouseArea{
anchors.fill: parent
onClicked: {
springAni1.from = rect.x;
springAni1.to = mouse.x - 20;
springAni1.start();
springAni2.from = rect.y;
springAni2.to = mouse.y - 20;
springAni2.start();
}
}
}
組合動畫:
略
State:
在QML中,狀態是定義在State類型中的一系列屬性配置。不同的配置可能有不同的作用:
1,顯示一些UI組件,隱藏另一些
2,想用戶呈現不同的操作和功能
3,啟動,暫停,停止動畫
4,在某種新的狀態下執行某些腳本
5,改變某個特定Item的property的值
6,顯示一個不同的view或screen
等等...
代碼:
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 360
height: 240
color: "#eee"
Text {
id: centerTxt
text: qsTr("Just a text!")
anchors.centerIn: parent
font.pixelSize: 24
MouseArea{
id:mouseArea
anchors.fill: parent
onPressed: {
centerTxt.state = "blueText";
}
onReleased: {
centerTxt.state = "redText";
}
}
state:"redText"
states: [
State {
name: "redText"
changes: [
PropertyChanges {
target: centerTxt
color:"red"
}
]
},
State {
name: "blueText"
PropertyChanges {
target: centerTxt
color:"blue"
}
}
]
}
}
}
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.12
Window {
id: root
visible: true
title: qsTr("Hello World")
width: 800
height: 600
Rectangle{
id:rect
width: 360
height: 240
color: "#eee"
Text {
id: centerTxt
text: qsTr("Just a text!")
anchors.centerIn: parent
font.pixelSize: 24
MouseArea{
id:mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
}
state:"redText"
states: [
State {
name: "redText"
when:mouseArea.pressedButtons === Qt.RightButton
changes: [
PropertyChanges {
target: centerTxt
color:"red"
},
PropertyChanges {
target: centerTxt
font.bold:true
font.italic: true
}
]
},
State {
name: "blueText"
when: mouseArea.pressed
PropertyChanges {
target: centerTxt
color:"blue"
font.pixelSize: 48;
}
}
]
}
}
}
C++ 與 QML 混合編程:
在QML中使用c++ 類和對象:
要想將一個類或對象導出到QML,前提條件是:
1,從QObject 或 QObject 的派生類繼承
2,使用Q_OBJECT 宏
省略...
在QML中使用c++ 類和對象:
