C++ 入門指南 4.01
單元 26 - MVC 模式與 QML
以 MVC 模式來看我們發展的專案 (project) , M 是指 Encrypt 類別 (class) ,也就是我們已經開發好的 encrypt.cpp , V 為 Qt Creator 自動產生的 main.qml , C 則是 encryptcontroll.cpp
View → main.qml
Controller → encryptcontroll.cpp
由於 Qt 預設的 C++ 程式副檔名 (file extension) 為 .cpp ,因此這裡將原本 .cxx 副檔名換成 .cpp 。
我們在這個單元內先來看看 Qt Quick 專案的預設 QML 檔案,從在 Qt Creator 中建立新專案,預設建立的 QML 檔案 main.qml 如下
import QtQuick Window { width: 640 height: 480 visible: true title: qsTr("Hello World") }
執行會得到以下的視窗
簡單說,以上視窗就是標題列為 Hello World 的 640×480 的空白視窗,這裡我們好好來看看 main.qml , QML 檔案首先要引入 QtQuick
import QtQuick
底下 Window 就是 QML 當中視窗的型態 (type) ,視窗元件的型態要放在 Window 底下的大括弧中
Window {
不過預設的 QML 程式碼並沒有視窗元件,底下我們會舉另一個有視窗元件的例子,這裡大括弧裡頭是 Window 的屬性,首先視窗寬 width 設定為 640 ,高 height 設定為 480
width: 640 height: 480
然後是否可見的 visible 設定為 true ,注意 visible 預設為 false ,如果沒有把 visible 設定為 true ,視窗就不會顯示
visible: true
接下來設定標題列 title ,這裡用到了 qsTr() , qsTr() 的目的主要是幫助 QML 程式在地化 (localization) ,基本上 QML 預設字串 (string) 使用 qsTr()
title: qsTr("Hello World")
Qt Quick 預設的程式碼很簡單,除了設定標題列之外,並沒有加入其他的視窗元件,如果要加入其他的視窗元件, QML 採取的是物件層級 (object hierarchy) 模式,下面以加入選單列及一個按鈕的 Qt QML Demo 說明如何定義 QML 的物件層級
import QtQuick import QtQuick.Controls Window { width: 400 height: 200 title: qsTr("Qt QML Demo") visible: true // 設定選單列 MenuBar { Menu { title: qsTr("功能") MenuItem { text: qsTr("&改變") onTriggered: button.text = "改變" } MenuItem { text: qsTr("關閉") onTriggered: Qt.quit(); } } } // 按鈕視窗元件 Button { id: button text: qsTr("按鈕") anchors.centerIn: parent onClicked: { button.text = "按鈕" } } } /* 《程式語言教學誌》的範例程式 http://kaiching.org/ 檔名:main.qml 功能:示範 QML 的物件層級 作者:張凱慶 */
此為標題列 Qt QML Demo 的 400×200 視窗,首先看到「設定選單列」的部分
// 設定選單列 MenuBar { Menu { title: qsTr("功能") MenuItem { text: qsTr("改變") onTriggered: button.text = "改變" } MenuItem { text: qsTr("關閉") onTriggered: Qt.quit(); } } }
MenuBar 是在 Window 底下的第一個物件 (object) , MenuBar 底下又有 Menu , Menu 底下則是有 MenuItem ,形成如下的物件層級
↓
MenuBar
↓
Menu
↓
MenuItem
一旦加入 MenuBar ,就會在視窗中呈現選單列,然後 Menu 是個別的選單, MenuItem 就是選單中的選項,執行後如下圖
Menu 底下的 title 就是選單名稱
title: qsTr("功能")
然後有兩個 MenuItem , MenuItem 就是選項, text 是選項的文字, onTriggered 則是點擊選項執行的 JavaScript 程式碼,底下是第一個 MenuItem 的 text 及 onTriggered
text: qsTr("改變") onTriggered: button.text = "改變"
第一個選項是「改變」,點擊選項執行的 JavaScript 程式碼是把 button 的 text 設定為 "改變" , button 則是底下按鈕視窗元件的 id
// 按鈕視窗元件 Button { id: button text: qsTr("按鈕") anchors.centerIn: parent onClicked: { button.text = "按鈕" } }
先注意到 Buuton 定義在 QtQuick.Controls 中,所以上面要先引入 QtQuick.Controls
import QtQuick.Controls
使用 Button 的 id 就可以控制 Buton ,這裡 anchors 則是對齊方式
anchors.centerIn: parent
centerIn 表示要置中的視窗元件, parent 表示上一級視窗元件,也就是 Window ,因此這個按鈕會顯示在 400×200 視窗的中心。
下面 onClicked 表示按下按鈕後執行的 JavaScript 程式碼,這裡是把按鈕文字重新設定回 "按鈕"
onClicked: { button.text = "按鈕" }
回到「功能」選單的第二個選項
MenuItem { text: qsTr("關閉") onTriggered: Qt.quit(); } }
這個選項的文字是「關閉」,也就是利用 Qt.quit() 關閉視窗,結束程式執行。
以上我們對 Qt Quick 專案中的 QML 做了個概略性的介紹,下一個單元,我們來討論如何用 QML 設計我們 Encrypt 類別的 GUI 囉!
中英文術語對照 | |
---|---|
類別 | class |
副檔名 | extension |
在地化 | localization |
物件 | object |
物件層級 | object hierarchy |
專案 | project |
字串 | string |
型態 | type |
重點整理 |
---|
1. 專案 encrypt_gui 中, M 是指 encrypt.cpp 中的 Encrypt 類別, V 為 Qt Creator 自動產生的 main.qml , C 則是 encryptcontroll.cpp 。 |
2. QML 中 Window 型態的屬性可以設定視窗的寬 width 、高 height 、是否可見 visible 與標題列 title 等等。 |
3. QML 的物件層級是指從最外層的型態 Window 開始, Window 底下的大括弧可以再定義視窗元件的型態,不同視窗元件裡頭可以再包含各自的視窗元件,上層可用 parent 代替。 |
4. QML 設定選單列的型態為 MenuBar ,選單為 Menu ,選項為 MenuItem , Menu 的 title 為選單名稱, MenuItem 的 text 為選項文字, onTriggered 可設置需要的 JavaScript 程式碼。 |
5. QML 設定按鈕的型態為 Buuton , text 為按鈕文字, anchors 設定對齊方式, onClicked 設定按下按鈕所要執行的 JavaScript 程式碼。 |
6. qstr() 的目的是實現語言在地化的功能。 |
7. 如果要操控某個 QML 型態,可在型態中定義 id ,然後利用 JavaScript 進行控制。 |
8. QML 的物件層級是讓視窗元件有上下的關係,大視窗元件包含小視窗元件,大視窗元件屬於上層,小視窗元件就屬於下層。 |
9. QML 中利用 JavaScript 呼叫 Qt.quit() 就會結束程式執行。 |
問題與討論 |
---|
1. 什麼是 MVC 模式?為什麼要用 MVC 模式開發 GUI 軟體? |
2. Qt Quick 專案跟原先 Qt Widgets 專案有何不同? |
3. 什麼是 QML ?為什麼要用 QML 設計 GUI ? |
4. 什麼是 QML 的物件層級?為什麼要用物件層級? |
5. 想一想,如果 App 要實現多國語言版本可以怎麼做在地化? |
6. QML 為什麼要整合 JavaScript ?整合 JavaScript 有什麼優點? |
練習 |
---|
1. QML 中的 Rectangle 型態是長方形的視窗元件,建立一個 QtQuick 的 rectangle_demo1 專案,在 Window 中建立四個 Rectangle ,利用 color 指定顏色, width 指定寬度, height 指定寬度, x 指定在 window 中的 x 座標, y 指定在 window 中的 y 座標。 參考程式碼 |
2. 承上題, Rectangle 裡可以包含其他的視窗元件,建立一個 QtQuick 的 rectangle_demo2 專案,在 Rectangle 加入兩層的 Rectangle 。 參考程式碼 |
3. QML 中的 Flow 型態可以讓裡面的視窗元件呈現流動式的編排,建立一個 QtQuick 的 flow_demo 專案,裡面先建立 Flow 型態,然後在 Flow 中逐字元用 Text 顯示 "There is no spoon." , Text 用 text 設定顯示字元,另外可用 font.pixelSize 設定自行尺寸。 參考程式碼 |
4. QML 中的 Column 型態可以讓視窗元件呈現從上而下排列的直欄效果,建立一個 QtQuick 的 column_demo 專案,裡面先建立 Column 型態,然後在 Cloumn 中建立兩個 Button 。 參考程式碼 |
5. 承上題, Row 型態可以讓視窗元件呈現從上而下排列的直欄效果,建立一個 QtQuick 的 row_demo 專案,裡面先建立 Row 型態,然後在 Row 中建立兩個 Button 。 參考程式碼 |
6. 承上題,利用 Column 及 Row 就可以呈現格子狀的編排方式,建立一個 QtQuick 的 cr_demo 專案,裡面先建立 Column 型態,然後依次建立兩個 Row 型態,每個 Row 當中建立兩個 Button 。 參考程式碼 |
7. 承上題, Grid 型態可以直接用來呈現格子狀的編排方式,建立一個 QtQuick 的 grid_demo 專案,裡面先建立 Grid 型態,然後將 cloumns 設定為 2 ,繼續在 Grid 裡面建立 4 個 Button 。 參考程式碼 |
8. QML 中的 StackView 型態是堆疊式的視窗元件,也就是內容像卡片一樣,一張一張堆起來,然後就是以抽換卡片的方式來顯示內容,建立一個 QtQuick 的 stack_demo 專案,先將 Window 換成 ApplicationWindow ,然後建立 Stack 型態,將 id 設定為 stack , initialItem 設定為 mainView , anchors.fill 設定為 parent ,然後建立一個 Component ,將 Component 的 id 設定為 mainWindow ,然後建立兩個 Button ,一個加一,另一個減一,加一按鈕的 onClicked 設定為 stack.push(mainView) ,減一按鈕設定為 stack.pop() ,最後在建立一個 Text ,將 text 設定為 stack.depth 。 參考程式碼 |
9. QML 中的 SwipeView 型態是可以用左右分頁的方式呈現內容,建立一個 QtQuick 的 swipe_demo 專案,先將 Window 換成 ApplicationWindow ,然後建立 SwipeView 型態,將 id 設定為 view , currentIndex 設定為 0 ,然後用三個 Item 建立三個頁面, Item 是類似 Component 的視窗元件,可以在裡頭添加其他的視窗元件,最後建立 PageIndicator ,這是顯示第幾頁的效果, id 設定為 indicator , count 設定為 view.count , currentIndex 設定為 view.currentIndex ,另外可設定 anchors 來呈現在視窗中的位置。 參考程式碼 |
10. QML 中的 ScrollView 型態可以其內的內容超過寬度及高度的時候呈現卷軸,建立一個 QtQuick 的 scroll_demo 專案,將 ApplicationWindow 的 width 設定為 400 , height 設定為 200 ,然後建立 ScrollView , anchors.fill 設定為 parent , clip 設定為 true ,裡面繼續建立一個 Label , text 設定為 qsTr("There\nis\nno\nspoon.") , font.pixelSize 設定為 200 。 參考程式碼 |
相關教學影片