qml基礎學習 基礎概念


一、概括

    學習qt已有2年多的時間,從qt4.7開始使用直到現在正在使用的qt5.6,基本都在windows機器上做開發。最近有意向看了下qt的qml部分,覺着還是挺不錯的,畢竟可以做嵌入式移動端產品的部分,還是值的一學。后來在網上看了一些資料,算是初步了解了下qml,所以想就自己學習的過程做以記錄,也方便自己理解,如果你有機會看到這篇文章,那么我認為你也是來學習qml的,如果你已經是一個有很強qml開發經驗的老手,那么這篇文章和接下來的qml學習系列的文章你都不用看下去了,呵呵。。。

    關於qml的由來,個人覺着Qt的Script、Quick、QML的關系與總結講的不錯,有興趣的同學可以去看下。

    qml的學習過程我主要是以Qt 學習之路 2博客和QmlBook-In-Chinese這本書為主,同時在做小示例的時候查閱幫助文檔。每個人的學習方式都不太一樣,如果你有更好的辦法可以留言。

二、效果預覽

    如下有4張效果圖,分別是4個小示例,關於demo后續章節會有解說,但是都是以代碼中的注解為主,有興趣的同學也可以直接下載示例程序,使用qt提供的qmlscene.exe來直接執行qml文件,或者qmlviewer.exe也可以預覽qml文件。

圖1 轉動的組件

圖2 紅綠燈1

圖3 紅綠燈2

圖4 GridView使用

三、學習qml必備

  1. 基本元素
  2. 組件,基本元素的復合
  3. 定位器(布局)
  4. 元素布局,錨
  5. 輸入元素,一行和多行
  6. quick現有組件
  7. 模型和視圖
  8. Canvas元素

1、基本元素

    QML 基本元素可以分為可視元素和不可視元素兩類。可視元素:ItemRectangleTextImage不可見元素:MouseArea關於MouseArea是不可見元素這一點我需要強調一下,因為上邊我提到的兩篇學習文章都沒有說清楚,圖5是qt5.7的幫助文檔截圖,從圖中我們一眼就能看出結果,MouseArea確實是不可見元素。

圖5 MouseArea幫助文檔

    關於基本元素我覺着qmlbook這本書相關章節的最后一段說的很有意思,特此說明,如圖6所示

圖6 qml顯示和交互分開

    理解這些基本元素,你可以認為他們是一個個被封裝好的類,而且他們有非常之多的屬性,這里我就不介紹了,因為幫助文檔說的太清楚了。

2、組件

    組件其實就是基本元素的復合,放到一個單獨的文件,方便我們以后重用,關於怎么創建組件,本節的后續我會給出自己做的示例程序,代碼很簡單只是為了說明問題

3、定位器

    定位器主要有 RowColumnGridFlow等。

4、元素布局

    除了定位器,我們還可以使用錨(anchor)來布局元素

5、輸入元素

    鍵盤輸入的兩個元素:TextInputTextEdit。TextInput為一行輸入,TextEdit為多行輸入

6、quick組件

    如表1是Qt Quick Controls 1.1 提供的組件

ApplicationWindow 對應QMainWindow,提供頂層應用程序窗口
MenuBar 對應QMenuBar,提供窗口頂部橫向的菜單欄
StatusBar 對應QStatusBar,提供狀態欄
ToolBar 對應QToolBar,提供工具欄,可以添加ToolButton和其它組件
Action 對應QAction,提供能夠綁定到導航和視圖的抽象的用戶界面動作
導航和視圖
方便用戶在一個布局中管理和顯示其它組件
ScrollView 對應QScrollView,提供滾動視圖
SplitView 對應QSplitter,提供可拖動的分割視圖布局
StackView 對應QStackedWidget,提供基於棧的層疊布局
TabView 對應QTabWidget,提供帶有標簽的基於棧的層疊布局
TableView 對應QTableWidget,提供帶有滾動條、樣式和表頭的表格
控件
控件用於表現或接受用戶輸入
BusyIndicator 提供忙等示意組件
Button 對應QPushButton,提供按鈕組件
CheckBox 對應QCheckBox,提供復選框
ComboBox 對應QComboBox,提供下拉框
GroupBox 對應QGroupBox,提供帶有標題、邊框的容器
Label 對應QLabel,提供標簽組件
ProgressBar 對應QProgressBar,提供進度條組件
RadioButton 對應QRadioButton,提供單選按鈕
Slider 對應QSlider,提供滑動組件
SpinBox 對應QSpinBox,提供微調組件
Switch 提供類似單選按鈕的開關組件
TextArea 對應QTextEdit,提供能夠顯示多行文本的富文本編輯框
TextField 對應QTextLine,提供顯示單行文本的純文本編輯框
ToolButton 對應QToolButton,提供在工具欄上顯示的工具按鈕
ExclusiveGroup 提供互斥
菜單
用於構建菜單的組件
Menu 對應QMenu,提供菜單、子菜單、彈出菜單等
MenuSeparator 提供菜單分隔符
MenuItem 提供添加到菜單欄或菜單的菜單項
StatusBar 對應QStatusBar,提供狀態欄
ToolBar 對應QToolBar,提供工具欄,可以添加ToolButton和其它組件

表1 Qt Quick Controls 1.1組件

7、模型和視圖

    模型和視圖其實屬於qml的高級使用部分了,但是為了能早些理解qml的東西,我提前拿出一些簡單的東西,預先學習下。

8、canvas畫布

    在早些qt4時代,qml只提供了幾種基礎元素,第一小節也說明了,有很多人期望的圓角矩形,橢圓和圓,但是最終官方沒有給出具體的元素,如果是要做這些組件,那么就需要設計師給切圖。到了qt5,官方提供了canvas畫布,這個畫布可以實現復雜的繪圖操作,並且畫布元素是基於HTML5的畫布元素來完成的。支持畫筆,填充,漸變,文本和繪制路徑創建命令。

四、小示例

    接下里就是第二節所展示的效果圖對於代碼講解了,那我也就按照上圖展示的順序一個個講解代碼

1、基礎組件講解

    在開始示例講解之前,我先說下我自己封裝的一個小組件,代碼量很少,只為說明問題,具體請看diamante

 1 import QtQuick 2.5
 2 
 3 // 圓角矩形框矩形框,支持點擊
 4 Rectangle {
 5     property alias text: name.text;//導出文本變量
 6     property alias textColor: name.color;//導出文本顏色
 7 
 8     id: root;
 9     width: 120;
10     height: 120;
11     radius:60;
12     antialiasing: true;
13     signal clicked();//自定義信號  外部可以通過onClicked接收
14 
15     MouseArea
16     {
17         width: root.width;
18         height: root.height;
19 
20         onClicked:
21         {
22             //鼠標點擊時發送消息 並輸入日志
23            root.clicked();
24             console.log("rectangle clicked");
25         }
26     }
27 
28     Text
29     {
30         id: name;
31         text: "";
32         color: "black";
33         anchors.centerIn: parent;
34     }
35 }

2、旋轉的風車,代碼里有多種方式實現矩形旋轉,具體使用那一種就由個人喜好了

import QtQuick 2.0
import QtQuick.Window 2.0
import QtGraphicalEffects 1.0

import "../contrl" //導入自定義組件模塊

Window {
    id:root;
    visible: true;
    width: 600;
    height: 400;

    //背景色窗口
    Rectangle {
        id: bg;
        color:"lightsteelblue";
        width: root.width;
        height:root.height;
    }
    //鼠標點擊背景色時停止旋轉圖形
    MouseArea {
        width: bg.width;
        height: bg.height;

        onClicked: {
            ro.pause();
        }
    }

    //自定義控件  通過import導入
    Rect
    {
        id: roundItem;
        anchors.centerIn: parent;
        //漸變填充矩形
        ConicalGradient
        {
            anchors.fill: parent
            gradient: Gradient {
                GradientStop { position: 0.0; color: "lightsteelblue" }
                GradientStop { position: 1.0; color: "blue" }
            }
        }
        //旋轉動畫1  程序剛啟動會執行 原因未知
        //        NumberAnimation on rotation {
        //            loops:Animation.Infinite;
        //            from:0;
        //            to:360;
        //            duration: 1000;
        //        }


        //旋轉動畫2  配合wheel.rotation = 360;使用  動畫 不能循環執行
        //        Behavior on rotation {
        //            NumberAnimation {
        //                loops:Animation.Infinite;//無效
        //                duration: 1000;
        //            }
        //        }

        //旋轉動畫3  相比於動畫1  在屬性中主動指明了target和property
        //        NumberAnimation {
        //            id:ro;
        //            loops:Animation.Infinite;
        //            property: "rotation";
        //            target:roundItem;
        //            from:0;
        //            to:360;
        //            duration: 1000;
        //        }

        //旋轉動畫4  和動畫1是一樣的  因為RotationAnimation和NumberAnimation都是繼承自PropertyAcimation
        //因此RotationAnimation動畫可以實現和動畫2一樣的效果,使用RotationAnimation
        //        RotationAnimation on rotation {
        //            loops: Animation.Infinite;
        //            from: 0;
        //            to: 360;
        //            duration: 1000;
        //        }

        //旋轉動畫5
        RotationAnimation {
            id:ro;
            target:roundItem;
            loops: Animation.Infinite;
            from: 0;
            to: 360;
            duration: 1000;
        }

        onClicked: {
            if (ro.paused)
            {
                ro.resume();
            }
            else
            {
                ro.start();
            }
        }
    }
}

3、紅綠燈,下述代碼紅色的的切換時通過鼠標單擊進行

  1 import QtQuick 2.0
  2 import QtQuick.Window 2.0
  3 import QtGraphicalEffects 1.0
  4 
  5 import "../contrl"
  6 
  7 Window
  8 {
  9     function dosomething()//測試script腳本運行效果
 10     {
 11         console.log("do something");
 12     }
 13 
 14     id:root;
 15     visible: true;
 16     width: 370;
 17     height: 130;
 18 
 19     Rectangle
 20     {
 22         id:rootRect;
 23         width: root.width;
 24         height:root.height;
 25         anchors.centerIn:parent;
 26 
 27         Row
 28         {
 29             id:ligheGroup;
 30             spacing: 2;
 31             states:
 32             [
 33                 State {
 34                     name: "red"
 35                //     StateChangeScript {name: "myScript"; script: dosomething(); }  //可以正常調用
 36                     PropertyChanges {
 37                         target: redLight; color:"red";
 38                     }
 39                     PropertyChanges {
 40                         target: greenLight; color:"black";
 41                     }
 42                     PropertyChanges {
 43                         target: yellowLight; color:"black";
 44                     }
 45                 },
 46                 State {
 47                     name: "green"
 48                     PropertyChanges {
 49                         target: redLight; color:"black";
 50                     }
 51                     PropertyChanges {
 52                         target: greenLight; color:"green";
 53                     }
 54                     PropertyChanges {
 55                         target: yellowLight; color:"black";
 56                     }
 57                 },
 58                 State {
 59                     name: "yellow"
 60                     PropertyChanges {
 61                         target: redLight; color:"black";
 62                     }
 63                     PropertyChanges {
 64                         target: greenLight; color:"black";
 65                     }
 66                     PropertyChanges {
 67                         target: yellowLight; color:"yellow";
 68                     }
 69                 }
 70             ]
 71 
 72             anchors.centerIn:parent;
 73             Rect//紅燈
 74             {
 75                 id:redLight;
 76                 color:"black";
 77                 radius: width/2;
 78             }
 79             Rect//綠燈
 80             {
 81                 id:greenLight;
 82                 color:"black";
 83                 radius: width/2;
 84             }
 85             Rect//黃燈
 86             {
 87                 id:yellowLight;
 88                 color:"black";
 89                 radius: width/2;
 90             }
 91 
 92             transitions:
 93             [
 94                 Transition //提供從red狀態到yellow狀態的漸變過程
 95                 {
 96                     from: "red"
 97                     to: "yellow"
 98               //      ScriptAction { script: dosomething(); }  //可以正常調用
 99                     ColorAnimation{ target: redLight; properties: "color";duration: 1000;}
100                     ColorAnimation{ target: yellowLight; properties: "color";duration: 1000;}
101                 }
102             ]
103         }
104         property bool m_bIsRed : false;
105         MouseArea
106         {
107             anchors.fill: parent;
108             onClicked://鼠標點擊時,狀態切換
109             {
110                 if (ligheGroup.state == "red"
111                         || ligheGroup.state == "green")
112                 {
113                     ligheGroup.state = "yellow";
114                 }
115                 else
116                 {
117                     if (parent.m_bIsRed == false)
118                     {
119                         ligheGroup.state = "red";
120                         parent.m_bIsRed = true;
121                     }
122                     else
123                     {
124                         ligheGroup.state = "green";
125                         parent.m_bIsRed = false;
126                     }
127                 }
128             }
129         }
130     }
131 }

4、紅綠燈,不同於上述紅綠燈,次紅綠燈只需要鼠標單擊觸發運行,狀態是由定時器來控制,紅燈運行60秒,綠燈20秒,黃燈3秒,為了程序的迅速反應,在紅燈和綠燈的時候定時器觸發頻率所有提高,具體請看代碼,此處我只貼出定時器部分,如果需要整個運行程序,可自行下載demo。

 1 property bool m_bIsRed : false;//是否是紅燈亮
 2     property int m_iTicker : 0;
 3 
 4     Timer
 5     {
 6         id:redState;
 7         interval: 50;//每隔50毫秒觸發一次,真實情況下本應該是1000毫秒一次
 8         repeat: true;
 9         triggeredOnStart: true;
10         property int count : 60;//紅燈秒數
11 
12         onTriggered: {
13             if (lightGroup.state != "red")
14             {
15                 lightGroup.state = "red";
16                 root.m_bIsRed = true;
17             }
18 
19             ++m_iTicker;
20             redLight.text = count - m_iTicker;
21             if (count <= m_iTicker)//到達指定時間 重置計數器,並切換到黃燈定時器,關閉自身定時器
22             {
23                 m_iTicker = 0;
24                 yellowState.start();
25                 redState.stop();
26             }
27         }
28     }
29     Timer
30     {
31         id:yellowState;
32         interval: 1000;
33         repeat: true;
34         triggeredOnStart: true;
35         property int count : 3;//黃燈秒數
36 
37         onTriggered: {
38             if (lightGroup.state != "yellow")
39             {
40                 lightGroup.state = "yellow";
41             }
42             ++m_iTicker;
43             yellowLight.text = count - m_iTicker;
44             if (count <= m_iTicker)//到達指定時間 重置計數器,並切換到綠燈/紅燈定時器,關閉自身定時器
45             {
46                 m_iTicker = 0;
47                 if (m_bIsRed)
48                 {
49                     greenState.start();
50                 }
51                 else
52                 {
53                     redState.start();
54                 }
55                 stop();
56             }
57         }
58     }
59     Timer
60     {
61         id: greenState;
62         interval: 150;//每隔150毫秒觸發一次,真實情況下本應該是1000毫秒一次
63         repeat: true;
64         triggeredOnStart: true;
65         property int count : 20;//綠燈秒數
66 
67         onTriggered: {
68             if (lightGroup.state != "green")
69             {
70                 lightGroup.state = "green";
71                 root.m_bIsRed = false;
72             }
73 
74             ++m_iTicker;
75             greenLight.text = count - m_iTicker;
76             if (count <= m_iTicker)//到達指定時間 重置計數器,並切換到黃燈定時器,關閉自身定時器
77             {
78                 m_iTicker = 0;
79                 yellowState.start();
80                 greenState.stop();
81             }
82         }
83     }

5、日歷窗口,代碼量不大,有興趣的可以看看,主要就是界面展示,如果想要做到動態的日歷,需要對模型動態的增刪,這個功能后續我們在完善。

 1 import QtQuick 2.6
 2 import QtQuick.Window 2.0
 3 import QtGraphicalEffects 1.0
 4 
 5 import "../contrl"
 6 
 7 Window
 8 {
 9     visible: true;
10     width: 300;
11     height: 300;
12 
13     Rectangle
14     {
15         id:root;
16         anchors.fill: parent;
17         width: root.width;
18         height: root.height;
19         color: "yellow";
20 
21         //日期頭
22         Row
23         {
24             id: weekname;
25             spacing: 2;
26             padding: 5;
27 
28             Repeater
29             {
30                 model: ["周天", "周一", "周二", "周三", "周四", "周五", "周六"]
31                 Rectangle
32                 {
33                     width: (root.width - 6 * weekname.spacing - 10) / 7;
34                     height: 30
35                     radius: 3
36                     color: "lightBlue"
37                     Text
38                     {
39                         anchors.centerIn: parent
40                         text: modelData
41                     }
42                 }
43             }
44         }
45 
46         //
47         GridView
48         {
49             id: weekday;
50             boundsBehavior: Flickable.StopAtBounds;
51             anchors//布局
52             {
53                 top: weekname.bottom;
54                 left:root.left;
55                 leftMargin:5;
56                 right: root.right;
57                 rightMargin:5;
58                 bottom: root.bottom;
59             }
60             model: 42;//天數
61 
62             cellWidth: (root.width - 10) / 7;
63             cellHeight: (root.width - 10) / 7;
64 //            Repeater
65 //            {
66 //                Rectangle
67 //                {
68 //                    radius: 8;
69 //                    color: "lightBlue";
70 //                    Text
71 //                    {
72 //                        anchors.centerIn: parent;
73 //                        text: modelData;
74 //                    }
75 //                }
76 //            }
77             delegate: numberDelegate;
78             focus: true;//可以獲取焦點
79         }
80 
81         Component//繪制代理
82         {
83             id: numberDelegate;
84             Rectangle
85             {
86                 width: weekday.cellWidth;
87                 height: weekday.cellHeight;
88                 color: GridView.isCurrentItem ? "green" : "lightGreen"//根據是否是當前項設置顏色
89                 border.color: Qt.lighter("green");
90                 Text
91                 {
92                     anchors.centerIn: parent;
93                     font.pixelSize: 10;
94                     text: index + 1;//文本取索引值
95                 }
96             }
97         }
98     }
99 }
View Code

    補充:示例代碼中:GridView中的repeater元素是不需要的,repeater是配合定位器使用的模型,因為每一個repeater都包含一個默認的繪制代理。

五、下載鏈接

    qml簡單示例

注:這是qml學習系列的第一篇文章,后邊我還會以這種示例的形式繼續更新更多學習的進度,希望大家多多支持,有問題的小伙伴可以私信我。謝謝。。。

 

如果您覺得文章不錯,不妨給個 打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。 


免責聲明!

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



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