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 World640×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 底下又有 MenuMenu 底下則是有 MenuItem ,形成如下的物件層級

Window

MenuBar

Menu

MenuItem

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

-encrypt_gui-

Menu 底下的 title 就是選單名稱

title: qsTr("功能")

然後有兩個 MenuItemMenuItem 就是選項, text 是選項的文字, onTriggered 則是點擊選項執行的 JavaScript 程式碼,底下是第一個 MenuItemtextonTriggered

text: qsTr("改變")
onTriggered: button.text = "改變"

第一個選項是「改變」,點擊選項執行的 JavaScript 程式碼是把 buttontext 設定為 "改變"button 則是底下按鈕視窗元件的 id

// 按鈕視窗元件
Button {
    id: button
    text: qsTr("按鈕")
    anchors.centerIn: parent

    onClicked: {
        button.text = "按鈕"
    }
}

先注意到 Buuton 定義在 QtQuick.Controls 中,所以上面要先引入 QtQuick.Controls

import QtQuick.Controls

使用 Buttonid 就可以控制 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 ,選項為 MenuItemMenutitle 為選單名稱, MenuItemtext 為選項文字, onTriggered 可設置需要的 JavaScript 程式碼。
5. QML 設定按鈕的型態為 Buutontext 為按鈕文字, 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."Texttext 設定顯示字元,另外可用 font.pixelSize 設定自行尺寸。 參考程式碼
4. QML 中的 Column 型態可以讓視窗元件呈現從上而下排列的直欄效果,建立一個 QtQuick 的 column_demo 專案,裡面先建立 Column 型態,然後在 Cloumn 中建立兩個 Button參考程式碼
5. 承上題, Row 型態可以讓視窗元件呈現從上而下排列的直欄效果,建立一個 QtQuick 的 row_demo 專案,裡面先建立 Row 型態,然後在 Row 中建立兩個 Button參考程式碼
6. 承上題,利用 ColumnRow 就可以呈現格子狀的編排方式,建立一個 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 設定為 stackinitialItem 設定為 mainViewanchors.fill 設定為 parent ,然後建立一個 Component ,將 Componentid 設定為 mainWindow ,然後建立兩個 Button ,一個加一,另一個減一加一按鈕的 onClicked 設定為 stack.push(mainView)減一按鈕設定為 stack.pop() ,最後在建立一個 Text ,將 text 設定為 stack.depth參考程式碼
9. QML 中的 SwipeView 型態是可以用左右分頁的方式呈現內容,建立一個 QtQuick 的 swipe_demo 專案,先將 Window 換成 ApplicationWindow ,然後建立 SwipeView 型態,將 id 設定為 viewcurrentIndex 設定為 0 ,然後用三個 Item 建立三個頁面, Item 是類似 Component 的視窗元件,可以在裡頭添加其他的視窗元件,最後建立 PageIndicator ,這是顯示第幾頁的效果, id 設定為 indicatorcount 設定為 view.countcurrentIndex 設定為 view.currentIndex ,另外可設定 anchors 來呈現在視窗中的位置。 參考程式碼
10. QML 中的 ScrollView 型態可以其內的內容超過寬度及高度的時候呈現卷軸,建立一個 QtQuick 的 scroll_demo 專案,將 ApplicationWindowwidth 設定為 400height 設定為 200 ,然後建立 ScrollViewanchors.fill 設定為 parentclip 設定為 true ,裡面繼續建立一個 Labeltext 設定為 qsTr("There\nis\nno\nspoon.")font.pixelSize 設定為 200參考程式碼

相關教學影片

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