C++ 入門指南 4.01

單元 26 - MVC 模式與 QML

-unit26-

以 MVC 模式來看我們發展的專案 (project) , M 是指 Encrypt 類別 (class) ,也就是我們已經開發好的 encrypt.cpp , V 為 Qt Creator 自動產生的 main.qml , C 則是 encryptcontroll.cpp

Model → encrypt.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")
}

執行會得到以下的視窗

-encrypt_gui-

簡單說,以上視窗就是標題列為 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 ,形成如下的物件層級

Window
↓
MenuBar
↓
Menu
↓
MenuItem

一旦加入 MenuBar ,就會在視窗中呈現選單列,然後 Menu 是個別的選單, MenuItem 就是選單中的選項,執行後如下圖

-encrypt_gui-

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 。 參考程式碼

相關教學影片

上一頁 單元 25 - Qt Creator 使用簡介
回 C++ 入門指南 4.01 目錄
下一頁 單元 27 - 使用 QML 設計視窗外觀
回 C++ 教材
回程式語言教材首頁